可持久化数据结构(平衡树trie树线段树) 总结
Posted loadingkkk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了可持久化数据结构(平衡树trie树线段树) 总结相关的知识,希望对你有一定的参考价值。
然而好像没有平衡树
还是题解包:
T1:森林
树上主席树+启发式合并。
然而好像知道标签就没啥了。在启发式合并时可以顺手求lca
然而这题好像可以时间换空间(回收空间)
T2:影魔
难点在于考虑贡献的来源
考虑一个区间两端点和区间最值(不含端点)的关系
小,中,大:贡献p1
大,小,大:贡献p2
大,中,小:贡献p1
则预处理出每个点左右第一个比它大的数的位置,设为l和r
则l会对r有p2的贡献,l会对i+1~r-1产生p1的贡献,同理r会对l+1~i-1产生p1的贡献。
用线段树维护扫描线,正向,逆向分别扫一遍,先把贡献都加进线段树,扫到某个点时先统计贡献再在线段树中减掉贡献。
具体实现见代码
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define N 200050 4 using namespace std; 5 struct node{int l,r,id;LL ans;}q[N]; 6 const int inf=1000000007; 7 int n,m,p1,p2; 8 int a[N]; 9 int l[N],r[N],dq[N],ba; 10 vector<pair<int,int> >v[N]; 11 #define pb push_back 12 #define mmp make_pair 13 #define F first 14 #define S second 15 inline bool cmp1(const node &a,const node &b){return a.l<b.l;} 16 inline bool cmp2(const node &a,const node &b){return a.r>b.r;} 17 inline bool cmp(const node &a,const node &b){return a.id<b.id;} 18 struct Segment_tree{ 19 LL sum[N<<2],tag[N<<2]; 20 inline void clear(){ 21 memset(sum,0,sizeof(sum)); 22 memset(tag,0,sizeof(tag)); 23 } 24 inline void upd(int g){sum[g]=sum[g<<1]+sum[g<<1|1];} 25 inline void down(int g,int l,int m,int r) 26 { 27 tag[g<<1]+=tag[g]; 28 tag[g<<1|1]+=tag[g]; 29 sum[g<<1]+=tag[g]*(m-l+1); 30 sum[g<<1|1]+=tag[g]*(r-m); 31 tag[g]=0;return; 32 } 33 inline void add(int g,int l,int r,int x,int y,int v){ 34 if(l>y||r<x)return; 35 if(l>=x&&r<=y){sum[g]+=v*(r-l+1);tag[g]+=v;return;} 36 const int m=l+r>>1; 37 if(tag[g])down(g,l,m,r); 38 add(g<<1,l,m,x,y,v); 39 add(g<<1|1,m+1,r,x,y,v); 40 upd(g); 41 } 42 inline LL ask(int g,int l,int r,int x,int y) 43 { 44 if(l>y||r<x)return 0; 45 if(l>=x&&r<=y)return sum[g]; 46 const int m=l+r>>1; 47 if(tag[g])down(g,l,m,r); 48 return ask(g<<1,l,m,x,y)+ask(g<<1|1,m+1,r,x,y); 49 } 50 }T; 51 int main() 52 { 53 // freopen("da.in","r",stdin); 54 scanf("%d%d%d%d",&n,&m,&p1,&p2); 55 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 56 for(int i=1;i<=m;++i) 57 scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i; 58 a[0]=inf;a[n+1]=inf-1; 59 60 for(int i=1;i<=n+1;++i){ 61 while(a[i]>a[dq[ba]]){ 62 r[dq[ba]]=i; 63 v[l[dq[ba]]].pb(mmp(dq[ba]+1,i-1)); 64 --ba; 65 } 66 l[i]=dq[ba];dq[++ba]=i; 67 } 68 // for(int i=1;i<=n;++i) 69 // printf("l[%d]=%d r[%d]=%d ",i,l[i],i,r[i]); 70 71 72 73 74 sort(q+1,q+m+1,cmp1); 75 for(int i=1;i<=n;++i){ 76 if(r[i]!=i+1)T.add(1,1,n,r[i],r[i],p1); 77 for(int j=v[i].size()-1;~j;--j) 78 T.add(1,1,n,v[i][j].F,v[i][j].S,p2); 79 } 80 for(int i=1,k=1;i<=n;++i){ 81 while(q[k].l==i&&k<=m){ 82 q[k].ans+=T.ask(1,1,n,i,q[k].r); 83 ++k; 84 } 85 if(r[i]!=i+1)T.add(1,1,n,r[i],r[i],-p1); 86 for(int j=v[i].size()-1;~j;--j) 87 T.add(1,1,n,v[i][j].F,v[i][j].S,-p2); 88 v[i].clear(); 89 } 90 91 for(int i=1;i<=n;++i) 92 if(r[i])v[r[i]].push_back(mmp(l[i]+1,i-1)); 93 sort(q+1,q+m+1,cmp2); 94 for(int i=n;i;--i){ 95 if(l[i]!=i-1)T.add(1,1,n,l[i],l[i],p1); 96 for(int j=v[i].size()-1;~j;--j) 97 T.add(1,1,n,v[i][j].F,v[i][j].S,p2); 98 } 99 for(int i=n,k=1;i;--i){ 100 while(q[k].r==i&&k<=m){ 101 q[k].ans+=T.ask(1,1,n,q[k].l,i); 102 ++k; 103 } 104 if(l[i]!=i-1)T.add(1,1,n,l[i],l[i],-p1); 105 for(int j=v[i].size()-1;~j;--j) 106 T.add(1,1,n,v[i][j].F,v[i][j].S,-p2); 107 } 108 // printf("%d %d %lld ",q[2].l,q[2].r,q[2].ans); 109 sort(q+1,q+m+1,cmp); 110 for(int i=1;i<=m;++i) 111 printf("%lld ",q[i].ans+1ll*(q[i].r-q[i].l)*p1); 112 return 0; 113 }
以上是关于可持久化数据结构(平衡树trie树线段树) 总结的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 4137 [FJOI2015]火星商店问题——线段树分治+可持久化01trie树
luogu P6088 [JSOI2015]字符串树 可持久化trie 线段树合并 树链剖分 trie树