线段树+主席树笔记
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大(树状数组套主席树)
本人暂时还不会……有时间再来填坑吧
以上是关于线段树+主席树笔记的主要内容,如果未能解决你的问题,请参考以下文章