模板三连击:树状数组+线段树+主席树
没事儿干,复习模板......
1.树状数组
本来不想写这个的,但是反正就几分钟就打完了,所以就写了,水AC数。
1 #include<cstdio> 2 3 typedef long long ll; 4 int n,m; 5 ll c[500005]; 6 7 int lb(int p) 8 { 9 return p&(-p); 10 } 11 12 void add(int p,int v) 13 { 14 for(int i=p;i<=n;i+=lb(i))c[i]+=(ll)v; 15 } 16 17 ll sum(int p) 18 { 19 ll ret=0; 20 for(int i=p;i;i-=lb(i))ret+=c[i]; 21 return ret; 22 } 23 24 int main() 25 { 26 scanf("%d%d",&n,&m); 27 for(int i=1;i<=n;i++) 28 { 29 int t; 30 scanf("%d",&t); 31 add(i,t); 32 } 33 for(int i=1;i<=m;i++) 34 { 35 int op,a,b; 36 scanf("%d%d%d",&op,&a,&b); 37 if(op==1)add(a,b); 38 if(op==2)printf("%lld\n",sum(b)-sum(a-1)); 39 } 40 return 0; 41 }
2.线段树
写个既有加法又有乘法的,怕忘了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 7 int n,m,mod; 8 int lb[400005],rb[400005]; 9 ll sum[400005],lza[400005],lzm[400005]; 10 int bv[100005]; 11 12 ll sz(int p) 13 { 14 return (ll)(rb[p]-lb[p]+1); 15 } 16 17 void pushup(int p) 18 { 19 sum[p]=(sum[p<<1]+sum[p<<1|1])%mod; 20 } 21 22 void build(int p,int l,int r) 23 { 24 lb[p]=l;rb[p]=r; 25 lza[p]=0;lzm[p]=1; 26 if(l==r) 27 { 28 sum[p]=(ll)bv[l]; 29 return; 30 } 31 int mid=(l+r)>>1; 32 build(p<<1,l,mid); 33 build(p<<1|1,mid+1,r); 34 pushup(p); 35 } 36 37 void pushdown(int p) 38 { 39 if(lza[p]==0&&lzm[p]==1)return; 40 sum[p<<1]=(sum[p<<1]*lzm[p]%mod+lza[p]*sz(p<<1)%mod)%mod; 41 sum[p<<1|1]=(sum[p<<1|1]*lzm[p]%mod+lza[p]*sz(p<<1|1)%mod)%mod; 42 lzm[p<<1]=lzm[p<<1]*lzm[p]%mod; 43 lzm[p<<1|1]=lzm[p<<1|1]*lzm[p]%mod; 44 lza[p<<1]=(lza[p<<1]*lzm[p]%mod+lza[p])%mod; 45 lza[p<<1|1]=(lza[p<<1|1]*lzm[p]%mod+lza[p])%mod; 46 lza[p]=0;lzm[p]=1; 47 } 48 49 void add(int p,int l,int r,int v) 50 { 51 if(lb[p]>=l&&rb[p]<=r) 52 { 53 sum[p]=(sum[p]+(sz(p)*(ll)v)%mod)%mod; 54 lza[p]=(lza[p]+v)%mod; 55 return; 56 } 57 pushdown(p); 58 int mid=(lb[p]+rb[p])>>1; 59 if(l<=mid)add(p<<1,l,r,v); 60 if(r>mid)add(p<<1|1,l,r,v); 61 pushup(p); 62 } 63 64 void mul(int p,int l,int r,int v) 65 { 66 if(lb[p]>=l&&rb[p]<=r) 67 { 68 sum[p]=sum[p]*(ll)v%mod; 69 lzm[p]=lzm[p]*(ll)v%mod; 70 lza[p]=lza[p]*(ll)v%mod; 71 return; 72 } 73 pushdown(p); 74 int mid=(lb[p]+rb[p])>>1; 75 if(l<=mid)mul(p<<1,l,r,v); 76 if(r>mid)mul(p<<1|1,l,r,v); 77 pushup(p); 78 } 79 80 ll query(int p,int l,int r) 81 { 82 if(lb[p]>=l&&rb[p]<=r)return sum[p]; 83 pushdown(p); 84 int mid=(lb[p]+rb[p])>>1; 85 ll ret=0; 86 if(l<=mid)ret+=query(p<<1,l,r); 87 if(r>mid)ret+=query(p<<1|1,l,r); 88 return ret%mod; 89 } 90 91 int main() 92 { 93 scanf("%d%d%d",&n,&m,&mod); 94 for(int i=1;i<=n;i++)scanf("%d",&bv[i]); 95 build(1,1,n); 96 for(int i=1;i<=m;i++) 97 { 98 int op; 99 scanf("%d",&op); 100 if(op==1) 101 { 102 int x,y,k; 103 scanf("%d%d%d",&x,&y,&k); 104 mul(1,x,y,k); 105 } 106 if(op==2) 107 { 108 int x,y,k; 109 scanf("%d%d%d",&x,&y,&k); 110 add(1,x,y,k); 111 } 112 if(op==3) 113 { 114 int x,y; 115 scanf("%d%d",&x,&y); 116 ll ans=query(1,x,y); 117 printf("%lld\n",ans); 118 } 119 } 120 return 0; 121 }
还有一道题跟这个几乎一模一样,只是需要先读入初始数组再读入操作数。
传送门在下面:
3.主席树
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n,m; 7 int rt[200005]; 8 int sum[4000005]; 9 int ls[4000005],rs[4000005],cnt; 10 int tv[200005]; 11 12 struct data 13 { 14 int rw,w,id; 15 }a[200005]; 16 17 int cmp(data q,data w) 18 { 19 return q.rw<w.rw; 20 } 21 22 int cmpb(data q,data w) 23 { 24 return q.id<w.id; 25 } 26 27 void edit(int &p,int bef,int l,int r,int v) 28 { 29 p=++cnt; 30 sum[p]=sum[bef]+1; 31 if(l==r)return; 32 ls[p]=ls[bef];rs[p]=rs[bef]; 33 int mid=(l+r)>>1; 34 if(v<=mid)edit(ls[p],ls[bef],l,mid,v); 35 else edit(rs[p],rs[bef],mid+1,r,v); 36 } 37 38 int ask(int pl,int pr,int l,int r,int rk) 39 { 40 if(l==r)return l; 41 int mid=(l+r)>>1; 42 int sz=sum[ls[pr]]-sum[ls[pl]]; 43 if(sz>=rk)return ask(ls[pl],ls[pr],l,mid,rk); 44 else return ask(rs[pl],rs[pr],mid+1,r,rk-sz); 45 } 46 47 int main() 48 { 49 scanf("%d%d",&n,&m); 50 for(int i=1;i<=n;i++)scanf("%d",&a[i].rw),a[i].id=i; 51 sort(a+1,a+n+1,cmp); 52 a[0].rw=-0x3f3f3f3f; 53 for(int i=1;i<=n;i++) 54 { 55 if(a[i].rw==a[i-1].rw)a[i].w=a[i-1].w; 56 else a[i].w=a[i-1].w+1,tv[a[i].w]=a[i].rw; 57 } 58 sort(a+1,a+n+1,cmpb); 59 for(int i=1;i<=n;i++)edit(rt[i],rt[i-1],1,n,a[i].w); 60 for(int i=1;i<=m;i++) 61 { 62 int l,r,k; 63 scanf("%d%d%d",&l,&r,&k); 64 int ans=ask(rt[l-1],rt[r],1,n,k); 65 printf("%d\n",tv[ans]); 66 } 67 return 0; 68 }
离散化的时候,忘把 a[0].rw 赋成-0x3f3f3f3f了,导致WA声一片......