首页 > 代码库 > 【复习笔记】主席树

【复习笔记】主席树

昨天在写带修改主席树的时候,咸鱼zcysky发现自己似乎根本不会写主席树

于是正好找个空复习下……

主席树的原理不用我扯了,主席树为啥能求k大,大概在它可以用历史版本存下区间的前缀和,求的时候差分下就能提出我要求的区间。

不过这么搞的话不要忘了离散化。

1.kth number

就是上面的裸题,不要手贱写bits就好。

技术分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #define N 100010
 4 #include<algorithm>
 5 #include<cstring>
 6 using namespace std;
 7 struct Node{int sum,ls,rs;}T[N*20];
 8 int cnt;
 9 void ins(int &num,int &x,int l,int r){
10     T[cnt++]=T[x];x=cnt-1;T[x].sum++;
11     if(l==r)return;
12     int mid=(l+r)/2;
13     if(num<=mid)ins(num,T[x].ls,l,mid);
14     else ins(num,T[x].rs,mid+1,r); 
15 }
16 int query(int i,int j,int k,int l,int r){
17     if(l==r)return l;
18     int t=T[T[j].ls].sum-T[T[i].ls].sum;
19     int mid=(l+r)/2;
20     if(k<=t)return query(T[i].ls,T[j].ls,k,l,mid);
21     else return query(T[i].rs,T[j].rs,k-t,mid+1,r);
22 }
23 struct A{
24     int x,idx;
25     bool operator<(const A &s)const{
26         return x<s.x;}
27 };
28 A a[N];
29 int rank[N],root[N];
30 int n,m;
31 int main(){
32     T[0].ls=T[0].rs=T[0].sum=0;root[0]=0;
33     while(scanf("%d%d",&n,&m)!=EOF){
34         for(register int i=1;i<=n;++i){
35             scanf("%d",&a[i].x);
36             a[i].idx=i;
37         }
38         sort(a+1,a+n+1);
39         for(int i=1;i<=n;i++)rank[a[i].idx]=i;
40         cnt=1;
41         for(int i=1;i<=n;i++){
42             root[i]=root[i-1];
43             ins(rank[i],root[i],1,n);
44         }
45         while(m--){
46             int i,j,k;
47             scanf("%d%d%d",&i,&j,&k);
48             int ans=a[query(root[i-1],root[j],k,1,n)].x;
49             printf("%d\n",ans);
50         }
51     }
52     return 0;
53 }
QAQ

哦注明下,这是我高一上学期写的,码风清奇……

不过总有人喜欢的。

 

2.luoogu P3567,bzoj3524 couriers(权限题)

真是的要什么权限题!洛谷提交地址

随手记录下size就好啦,不过这题甚至不用离散化23333

技术分享
 1 #include<bits/stdc++.h>
 2 #define N 500005
 3 using namespace std;
 4 int n,m,a[N],ls[25*N],rs[25*N],size[25*N],cnt=0,rt[N];
 5 void ins(int &o,int pre,int l,int r,int q){
 6     o=++cnt;int mid=(l+r)>>1;
 7     ls[o]=ls[pre];rs[o]=rs[pre];size[o]=size[pre]+1;
 8     if(l==r)return;
 9     if(q<=mid)ins(ls[o],ls[pre],l,mid,q);
10     else ins(rs[o],rs[pre],mid+1,r,q);
11 }
12 int query(int x,int y,int l,int r,int q){
13     if(l==r)return l;int mid=(l+r)>>1;
14     int lsize=(size[ls[x]]-size[ls[y]]),rsize=(size[rs[x]]-size[rs[y]]);
15     if(lsize>q)return query(ls[x],ls[y],l,mid,q);
16     else if(rsize>q)return query(rs[x],rs[y],mid+1,r,q);
17     else return 0;
18 }
19 inline int read(){
20     int f=1,x=0;char ch;
21     do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
22     do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
23     return f*x;
24 }
25 int main(){
26     n=read();m=read();
27     for(int i=1;i<=n;i++)a[i]=read();
28     for(int i=1;i<=n;i++)ins(rt[i],rt[i-1],1,n,a[i]);
29     while(m--){
30         int l=read(),r=read();
31         printf("%d\n",query(rt[r],rt[l-1],1,n,(r-l+1)>>1));
32     }
33     return 0;
34 }
点这里

3.mex

啥是mex?就是SG函数的mex啊。

之前写的莫队,后来发现主席树也很资瓷。

注意从0开始就好。

技术分享
 1 #include<bits/stdc++.h>
 2 #define N 300005
 3 #define M 6000005
 4 using namespace std;
 5 int n,q,cnt,a[N],ls[M],rs[M],rt[M],minv[M];
 6 void ins(int &x,int fa,int l,int r,int q,int val){
 7     x=++cnt;minv[x]=minv[fa];
 8     ls[x]=ls[fa];rs[x]=rs[fa];
 9     if(l==r){minv[x]=val;return;}
10     int mid=(l+r)>>1;
11     if(q<=mid)ins(ls[x],ls[fa],l,mid,q,val);
12     else ins(rs[x],rs[fa],mid+1,r,q,val);
13     minv[x]=min(minv[ls[x]],minv[rs[x]]);
14 }
15 int query(int x,int l,int r,int q){
16     if(l==r)return l;
17     int mid=(l+r)>>1;
18     if(minv[ls[x]]>=q)return query(rs[x],mid+1,r,q);
19     else return query(ls[x],l,mid,q);
20 }
21 inline int read(){
22     int f=1,x=0;char ch;
23     do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
24     do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
25     return f*x;
26 }
27 int main(){
28     n=read();q=read();
29     for(int i=1;i<=n;i++)a[i]=read();
30     for(int i=1;i<=n;i++)ins(rt[i],rt[i-1],0,1000000,a[i],i);
31     while(q--){
32         int x=read(),y=read();
33         printf("%d\n",query(rt[y],0,1000000,x));
34     }
35     return 0;
36 }
点这里的都是神犇!

4.dynamic ranking
详见之前blog。

技术分享
 1 #include<bits/stdc++.h>
 2 #define N 10005
 3 using namespace std;
 4 inline int lowbit(int x){return x&-x;}
 5 int n,m,sz,totn,totx,toty,a[N],b[N<<1],ca[N],cb[N],cc[N];
 6 int xx[N],yy[N],rt[N],size[600*N],ls[600*N],rs[600*N];
 7 void ins(int &o,int l,int r,int x,int q,int v){
 8     o=++sz;size[o]=size[x]+v;ls[o]=ls[x];rs[o]=rs[x];
 9     if(l==r)return;int mid=(l+r)>>1;
10     if(q<=mid)ins(ls[o],l,mid,ls[x],q,v);
11     else ins(rs[o],mid+1,r,rs[x],q,v);
12 }
13 int query(int l,int r,int q){
14     if(l==r)return l;
15     int sum=0,mid=(l+r)>>1;
16     for(int i=1;i<=totx;i++)sum-=size[ls[xx[i]]];
17     for(int i=1;i<=toty;i++)sum+=size[ls[yy[i]]];
18     if(q<=sum){
19         for(int i=1;i<=totx;i++)xx[i]=ls[xx[i]];
20         for(int i=1;i<=toty;i++)yy[i]=ls[yy[i]];
21         return query(l,mid,q);
22     }
23     else{
24         for(int i=1;i<=totx;i++)xx[i]=rs[xx[i]];
25         for(int i=1;i<=toty;i++)yy[i]=rs[yy[i]];
26         return query(mid+1,r,q-sum);
27     }
28 }
29 void add(int x,int v){
30     int k=lower_bound(b+1,b+totn+1,a[x])-b;
31     for(int i=x;i<=n;i+=lowbit(i))ins(rt[i],1,totn,rt[i],k,v);
32 }
33 inline int read(){
34     int f=1,x=0;char ch;
35     do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
36     do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
37     return f*x;
38 }
39 int main(){char s[20];
40     n=read();m=read();
41     for(int i=1;i<=n;i++)a[i]=read(),b[++totn]=a[i];
42     for(int i=1;i<=m;i++){
43         scanf("%s",s);ca[i]=read();cb[i]=read();
44         if(s[0]==Q)cc[i]=read();else b[++totn]=cb[i];
45     }
46     sort(b+1,b+totn+1);
47     totn=unique(b+1,b+totn+1)-b-1;
48     for(int i=1;i<=n;i++)add(i,1);
49     for(int i=1;i<=m;i++){
50         if(cc[i]){
51             totx=toty=0;
52             for(int j=ca[i]-1;j;j-=lowbit(j))xx[++totx]=rt[j];
53             for(int j=cb[i];j;j-=lowbit(j))yy[++toty]=rt[j];
54             printf("%d\n",b[query(1,totn,cc[i])]);
55         }
56         else{add(ca[i],-1);a[ca[i]]=cb[i];add(ca[i],1);}
57     }
58 }
带修改主席树

5.任务查询系统
这里是bzoj的地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3932

按照时间随意差分,差分完上树就行。

技术分享
 1 #include<bits/stdc++.h>
 2 #define N 100005
 3 using namespace std;
 4 int n,m,pre=1,totn,h[N],rt[N],cnt=0,ls[50*N],rs[50*N],size[50*N],sumv[50*N];
 5 vector<int>a[N];
 6 void ins(int &o,int pre,int l,int r,int q,int v){
 7     o=++cnt;ls[o]=ls[pre];rs[o]=rs[pre];
 8     size[o]=size[pre]+v;sumv[o]=sumv[pre]+h[q]*v;
 9     if(l==r)return;int mid=(l+r)>>1;
10     if(q<=mid)ins(ls[o],ls[pre],l,mid,q,v);
11     else ins(rs[o],rs[pre],mid+1,r,q,v);
12 }
13 int query(int o,int l,int r,int q){
14     if(q>=size[o])return sumv[o];
15     if(l==r)return sumv[o]/size[o]*q;
16     int mid=(l+r)>>1,ans=query(ls[o],l,mid,q);
17     if(q>size[ls[o]])ans+=query(rs[o],mid+1,r,q-size[ls[o]]);
18     return ans;
19 }
20 inline int read(){
21     int f=1,x=0;char ch;
22     do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
23     do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
24     return f*x;
25 }
26 int main(){
27     m=read();n=read();
28     for(int i=1;i<=m;i++){
29         int x=read(),y=read(),z=read();
30         a[x].push_back(z);a[y+1].push_back(-z);
31         h[i]=z;
32     }
33     sort(h+1,h+m+1);totn=unique(h+1,h+m+1)-h-1;
34     for(int i=1;i<=n;i++){
35         rt[i]=rt[i-1];
36         for(int j=0;j<a[i].size();j++){
37             int k=1;if(a[i][j]<0)k*=-1,a[i][j]*=-1;
38             ins(rt[i],rt[i],1,totn,lower_bound(h+1,h+totn+1,a[i][j])-h,k);
39         }
40     }
41     while(n--){
42         int X=read(),A=read(),B=read(),C=read();
43         printf("%d\n",pre=query(rt[X],1,totn,1+((long long)A*pre+B)%C));
44     }
45     return 0;
46 }
naive

啊呸这鬼题目,n,m怎么是反的啊!

为了这个sb错误找半天的zcysky是不是也是sb啊……

技术分享

【复习笔记】主席树