线段树+主席树笔记

Posted Altria Pendragon

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树+主席树笔记相关的知识,希望对你有一定的参考价值。

对不起,会打线段树是真的可以为所欲为的

线段树单点更新

 1 //求区间最值
 2 //n个元素,m个询问
 3 //C x y 代表将第x个元素的值改为y
 4 //D x y 代表在第x到第y个元素中找最大值 
 5 //X x y 代表在第x到第y个元素中找最小值
 6 #include<iostream>
 7 #include<cstring>
 8 #include<cstdio>
 9 #include<cmath>
10 using namespace std;
11 struct tree_node{
12     int maxn,minn;
13 }t[400001];
14 int n,m,x,y,a[100001];
15 char ord[5];
16 void build(int l,int r,int u){
17     if(l==r){
18         t[u].maxn=a[l];
19         t[u].minn=a[l];
20         return;
21     }
22     int mid=(l+r)/2;
23     build(l,mid,u*2);
24     build(mid+1,r,u*2+1);
25     t[u].maxn=max(t[u*2].maxn,t[u*2+1].maxn);
26     t[u].minn=min(t[u*2].minn,t[u*2+1].minn);
27 }
28 void updata(int l,int r,int u,int x,int y){
29     if(l==r){
30         t[u].maxn=y;
31         t[u].minn=y;
32         return;
33     }
34     int mid=(l+r)/2;
35     if(x<=mid)updata(l,mid,u*2,x,y);
36     else if(x>mid)updata(mid+1,r,u*2+1,x,y);
37     t[u].maxn=max(t[u*2].maxn,t[u*2+1].maxn);
38     t[u].minn=min(t[u*2].minn,t[u*2+1].minn);
39 }
40 int query_max(int l,int r,int u,int L,int R){
41     if(l>=L&&r<=R){
42         return t[u].maxn;
43     }
44     int mid=(l+r)/2,ans=-2147483647;
45     if(L<=mid)ans=max(ans,query_max(l,mid,u*2,L,R));
46     if(R>mid)ans=max(ans,query_max(mid+1,r,u*2+1,L,R));
47     return ans;
48 }
49 int query_min(int l,int r,int u,int L,int R){
50     if(l>=L&&r<=R){
51         return t[u].minn;
52     }
53     int mid=(l+r)/2,ans=2147483647;
54     if(L<=mid)ans=min(ans,query_min(l,mid,u*2,L,R));
55     if(R>mid)ans=min(ans,query_min(mid+1,r,u*2+1,L,R));
56     return ans;
57 }
58 int main(){
59     scanf("%d%d",&n,&m);
60     for(int i=1;i<=n;i++){
61         scanf("%d",&a[i]);
62     }
63     build(1,n,1);
64     for(int i=1;i<=m;i++){
65         scanf("%s",ord);
66         scanf("%d%d",&x,&y);
67         if(ord[0]==C){
68             updata(1,n,1,x,y);
69         }
70         if(ord[0]==D){
71             printf("%d\n",query_max(1,n,1,x,y));
72         }
73         if(ord[0]==X){
74             printf("%d\n",query_min(1,n,1,x,y));
75         }
76     }
77     return 0;
78 }

线段树区间修改

 1 //区间求和+区间修改
 2 //类似地,n个元素、m个询问 
 3 //Q x y表示询问x至y的和 
 4 //A x y z表示将x到y的值全部加上z
 5 #include<iostream>
 6 #include<cstring>
 7 #include<cstdio>
 8 #include<cmath>
 9 using namespace std;
10 struct tree{
11     int v,lazy;
12 }t[400001];
13 int n,m,x,y,z,a[100001];
14 char ord[5];
15 void pd(int u,int l,int r){
16     if(t[u].lazy!=0){
17         int mid=(l+r)/2;
18         t[u*2].lazy+=t[u].lazy;
19         t[u*2+1].lazy+=t[u].lazy;
20         t[u*2].v+=t[u].lazy*(mid-l+1);
21         t[u*2+1].v+=t[u].lazy*(r-mid);
22         t[u].lazy=0;
23     }
24 }
25 void build(int l,int r,int u){
26     if(l==r){
27         t[u].v=a[l];
28         return;
29     }
30     int mid=(l+r)/2;
31     t[u].lazy=0;
32     build(l,mid,u*2);
33     build(mid+1,r,u*2+1);
34     t[u].v=t[u*2].v+t[u*2+1].v;
35 }
36 void updata(int l,int r,int u,int L,int R,int val){
37     if(L<=l&&r<=R){
38         t[u].lazy+=val;
39         t[u].v+=val*(r-l+1);
40         return;
41     }
42     pd(u,l,r);
43     int mid=(l+r)/2;
44     if(L<=mid)updata(l,mid,u*2,L,R,val);
45     if(R>mid)updata(mid+1,r,u*2+1,L,R,val);
46     t[u].v=t[u*2].v+t[u*2+1].v;
47 }
48 int query(int l,int r,int u,int L,int R){
49     if(L<=l&&r<=R){
50         return t[u].v;
51     }
52     pd(u,l,r);
53     int mid=(l+r)/2,ans=0;
54     if(L<=mid)ans+=query(l,mid,u*2,L,R);
55     if(R>mid)ans+=query(mid+1,r,u*2+1,L,R);
56     t[u].v=t[u*2].v+t[u*2+1].v;
57     return ans;
58 }
59 int main(){
60     scanf("%d%d",&n,&m);
61     for(int i=1;i<=n;i++){
62         scanf("%d",&a[i]);
63     }
64     build(1,n,1);
65     for(int i=1;i<=m;i++){
66         scanf("%s%d%d",ord,&x,&y);
67         if(ord[0]==A){
68             scanf("%d",&z);
69             updata(1,n,1,x,y,z);
70         }
71         if(ord[0]==Q){
72             printf("%d\n",query(1,n,1,x,y));
73         }
74     }
75     return 0;
76 }

可持久化线段树单点修改

 1 //单点修改可持久化线段树(非主席树)
 2 //给出n个数,q个询问
 3 //每次询问形如 0 k l r 或 1 k i x
 4 //表示询问第k个版本l到r之间的最大值或把第k个版本的第i个数改为x
 5 //初始的n个数表示第一个版本 
 6 #include<iostream>
 7 #include<cstring>
 8 #include<cstdio>
 9 #include<cmath>
10 using namespace std;
11 struct node{
12     int mx,ls,rs;
13 }t[2000001];
14 int n,q,k,l,r,ord,cnt=0,tot=0,rt[100001],num[100001];
15 void build(int l,int r,int &u){
16     if(!u)u=++tot;
17     if(l==r){
18         t[u].mx=num[l];
19         return;
20     }
21     int mid=(l+r)/2;
22     build(l,mid,t[u].ls);
23     build(mid+1,r,t[u].rs);
24     t[u].mx=max(t[t[u].ls].mx,t[t[u].rs].mx);
25 }
26 void ins(int &k,int last,int l,int r,int p,int x){
27     t[k=++tot].mx=t[last].mx;
28     if(l==r){
29         t[k].mx=x;
30         return;
31     }
32     t[k].ls=t[last].ls;
33     t[k].rs=t[last].rs;
34     int mid=(l+r)/2;
35     if(p<=mid)ins(t[k].ls,t[last].ls,l,mid,p,x);
36     else ins(t[k].rs,t[last].rs,mid+1,r,p,x);
37     t[k].mx=max(t[t[k].ls].mx,t[t[k].rs].mx);
38 }
39 int query(int &k,int l,int r,int L,int R){
40     if(!k)return 0;
41     if(L==l&&r==R){
42         return t[k].mx;
43     }
44     int mid=(l+r)/2;
45     if(R<=mid)return query(t[k].ls,l,mid,L,R);
46     else if(L>mid)return query(t[k].rs,mid+1,r,L,R);
47     else return max(query(t[k].ls,l,mid,L,mid),query(t[k].rs,mid+1,r,mid+1,R));
48 }
49 int main(){
50     scanf("%d%d",&n,&q);
51     for(int i=1;i<=n;i++){
52         scanf("%d",&num[i]);
53     }
54     build(1,n,rt[++cnt]);
55     for(int i=1;i<=q;i++){
56         scanf("%d%d%d%d",&ord,&k,&l,&r);
57         if(ord==1){
58             ins(rt[++cnt],rt[k],1,n,l,r);
59         }else{
60             printf("%d\n",query(rt[k],1,n,l,r));
61         }
62     }
63     return 0;
64 }

可持久化线段树区间修改

 1 //hdu4348
 2 //标记永久化是真的省空间!!! 
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 typedef long long ll;
 9 struct node{
10     int ls,rs;
11     ll v,lazy;
12 }t[5000001];
13 int n,m,k,l,r,v,tot,cnt,num[100001],rt[100001];
14 char ord[3];
15 int build(int l,int r){
16     int u=++tot;
17     t[u].lazy=0;
18     if(l==r){
19         t[u].v=num[l];
20         return u;
21     }
22     int mid=(l+r)/2;
23     t[u].ls=build(l,mid);
24     t[u].rs=build(mid+1,r);
25     t[u].v=t[t[u].ls].v+t[t[u].rs].v;
26     return u;
27 }
28 int rebuild(int l,int r,int L,int R,int v,int k){
29     int u=++tot;
30     t[u].v=t[k].v;
31     t[u].ls=t[k].ls;
32     t[u].rs=t[k].rs;
33     t[u].lazy=t[k].lazy;
34     if(l==L&&r==R){
35         t[u].lazy+=v;
36         t[u].v+=v*(r-l+1);
37         return u;
38     }
39     int mid=(l+r)/2;
40     if(R<=mid)t[u].ls=rebuild(l,mid,L,R,v,t[k].ls);
41     else if(L>mid)t[u].rs=rebuild(mid+1,r,L,R,v,t[k].rs);
42     else{
43         t[u].ls=rebuild(l,mid,L,mid,v,t[k].ls);
44         t[u].rs=rebuild(mid+1,r,mid+1,R,v,t[k].rs);
45     }
46     t[u].v=t[t[u].ls].v+t[t[u].rs].v;
47     t[u].v+=t[u].lazy*(r-l+1);
48     return u;
49 }
50 ll query(int l,int r,int u,int L,int R){
51     if(l==L&&r==R){
52         return t[u].v;
53     }
54     int mid=(l+r)/2;
55     ll ans=0;
56     if(L>=l&&R<=r)ans+=t[u].lazy*(R-L+1);
57     else if(L<l&&R>=l&&R<=r)ans+=t[u].lazy*(R-l+1);
58     else if(R>r&&L>=l&&L<=r)ans+=t[u].lazy*(r-L+1);
59     else if(L<l&&R>r)ans+=t[u].lazy*(r-l+1);
60     if(R<=mid)ans+=query(l,mid,t[u].ls,L,R);
61     else if(L>mid)ans+=query(mid+1,r,t[u].rs,L,R);
62     else ans+=query(l,mid,t[u].ls,L,mid)+query(mid+1,r,t[u].rs,mid+1,R);
63     return ans;
64 }
65 int main(){
66     while(scanf("%d%d",&n,&m)!=EOF){
67         tot=cnt=0;
68         for(int i=1;i<=n;i++){
69             scanf("%d",&num[i]);
70         }
71         rt[0]=build(1,n);
72         for(int i=1;i<=m;i++){
73             scanf("%s",ord);
74             if(ord[0]==C){
75                 scanf("%d%d%d",&l,&r,&v);
76                 rt[cnt+1]=rebuild(1,n,l,r,v,rt[cnt]);
77                 cnt++;
78             }else if(ord[0]==Q){
79                 scanf("%d%d",&l,&r);
80                 printf("%lld\n",query(1,n,rt[cnt],l,r));
81             }else if(ord[0]==H){
82                 scanf("%d%d%d",&l,&r,&v);
83                 printf("%lld\n",query(1,n,rt[v],l,r));
84             }else{
85                 scanf("%d",&v);
86                 cnt=v;
87             }
88         }
89     }
90     return 0;
91 }

主席树求区间k大

 1 //Orz hjt
 2 //其实和可持久化线段树是还是有点区别的QAQ 
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstring>
 6 #include<cstdio>
 7 #include<cmath>
 8 using namespace std;
 9 struct node{
10     int ls,rs,v;
11 }t[2000001];
12 int n,q,k,l,r,pos,tot=0,cnt=0,a[100001],b[100001],rt[100001];
13 int build(int l,int r){
14     int u=++tot;
15     t[u].v=0;
16     if(l==r)return u;
17     int mid=(l+r)/2;
18     t[u].ls=build(l,mid);
19     t[u].rs=build(mid+1,r);
20     return u;
21 }
22 int ins(int l,int r,int k,int p){
23     int u=++tot;
24     t[u].ls=t[k].ls;
25     t[u].rs=t[k].rs;
26     t[u].v=t[k].v+1;
27     if(l==r)return u;
28     int mid=(l+r)/2;
29     if(p<=mid)t[u].ls=ins(l,mid,t[k].ls,p);
30     else t[u].rs=ins(mid+1,r,t[k].rs,p);
31     return u;
32 }
33 int query(int l,int r,int pre,int now,int k){
34     if(t[now].ls==t[now].rs){
35         return b[l];
36     }
37     int mid=(l+r)/2,tmp=t[t[now].ls].v-t[t[pre].ls].v;
38     if(tmp>=k)return query(l,mid,t[pre].ls,t[now].ls,k);
39     else return query(mid+1,r,t[pre].rs,t[now].rs,k-tmp);
40 }
41 int main(){
42     scanf("%d%d",&n,&q);
43     for(int i=1;i<=n;i++){
44         scanf("%d",&a[i]);
45         b[i]=a[i];
46     }
47     sort(b+1,b+n+1);
48     rt[0]=build(1,n);
49     for(int i=1;i<=n;i++)rt[i]=ins(1,n,rt[i-1],lower_bound(b+1,b+n+1,a[i])-b);
50     for(int i=1;i<=q;i++){
51         scanf("%d%d%d",&l,&r,&k);
52         printf("%d\n",query(1,n,rt[l-1],rt[r],k));
53     }
54     return 0;
55 }

带修改区间k大(树状数组套主席树)

本人暂时还不会……有时间再来填坑吧

以上是关于线段树+主席树笔记的主要内容,如果未能解决你的问题,请参考以下文章

主席树学习笔记

QDEZ集训笔记更新中

可持久化线段树(主席树)

P3834 模板可持久化线段树 1(主席树)

主席树

[数据结构] 主席树初识(理论,代码待补)