模板三连击:树状数组+线段树+主席树

没事儿干,复习模板......

1.树状数组

本来不想写这个的,但是反正就几分钟就打完了,所以就写了,水AC数。

洛谷 P3374 [模板]树状数组 1

 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.线段树

写个既有加法又有乘法的,怕忘了。

洛谷 P3373 [模板]线段树 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 }
线段树

还有一道题跟这个几乎一模一样,只是需要先读入初始数组再读入操作数。

传送门在下面:

洛谷 P2023 [AHOI2009]维护序列

3.主席树

 洛谷 P3834 [模板]可持久化线段树 1(主席树)

 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声一片......

猜你喜欢

转载自www.cnblogs.com/eternhope/p/9917103.html