HDU - 6087 Rikka with Sequence (可持久化treap+倍增+重构)

题目链接

感谢Dream_Lolita的题解,经过无数次失败的尝试之后终于AC了...

线段树是维护区间信息的强大工具,但它的形态是固定的,只支持修改和删除操作,不支持插入、反转、复制、分裂合并等操作,而treap支持。这道题有个区间复制的操作,因此只能用treap来代替了。

注意几个坑点:

1.对于操作2,当k<r-l+1时,不是将[l-k,r-k]中的元素直接替换到[l,r]上,而是将[l-k,l-1]中的元素复制多次再替换到[l,r]上,因此需要对[l-k,l-1]区间反复自我merge直至长度大于等于r-l+1,类似倍增的方式。

2.如果对每个结点设置一个静态的随机因子,那么对区间进行复制时,会产生大量重复的随机因子,严重影响树的平衡性。因此可以去掉随机因子,在对结点u,v进行merge的时候动态取一个随机数rnd,检查rnd%(siz[u]+siz[v])与siz[u]的关系来决定以哪种方式进行合并。考虑到评测OS是Windows,rand函数的上限只有2^15-1,因此可以采用rand()<<15|rand()的方法将两个rand函数拼凑起来,这样上限就扩大到2^30-1了。

3.操作3中的merge可以不用可持久化,但操作2中的merge必须可持久化,否则会出现莫名其妙的错误(这里查错查了很久,我暂时也说不清为什么)

4.本题对内存的限制非常严格,因此需要定期检查结点数量,如果快要超过内存上限了,就要对整个序列进行暴力重构。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=28e5+10,inf=0x3f3f3f3f;
 5 int ch[N][2],val[N],siz[N],tot,n,m,rt,A,q[200010],nq;
 6 ll sum[N];
 7 #define l(u) ch[u][0]
 8 #define r(u) ch[u][1]
 9 int rnd() {return rand()<<15|rand();}
10 int newnode(int x) {int u=++tot; val[u]=sum[u]=x,siz[u]=1,l(u)=r(u)=0; return u;}
11 int cpy(int u) {int w=++tot; val[w]=val[u],sum[w]=sum[u],siz[w]=siz[u],l(w)=l(u),r(w)=r(u); return w;}
12 void pu(int u) {siz[u]=siz[l(u)]+siz[r(u)]+1,sum[u]=sum[l(u)]+sum[r(u)]+val[u];}
13 void sp(int w,int k,int& u,int& v) {
14     if(!w) {u=v=0; return;}
15     if(k>=siz[l(w)]+1)u=cpy(w),sp(r(w),k-(siz[l(w)]+1),r(u),v),pu(u);
16     else v=cpy(w),sp(l(w),k,u,l(v)),pu(v);
17 }
18 void mg(int& w,int u,int v,int f=0) {
19     if(!u||!v) {w=u|v; return;}
20     if(rnd()%(siz[u]+siz[v])<siz[u])w=(f?cpy(u):u),mg(r(w),r(u),v,f);
21     else w=(f?cpy(v):v),mg(l(w),u,l(v),f);
22     pu(w);
23 }
24 void upd(int& u,int l,int r,int k) {
25     int L,M,R,M2;
26     sp(u,l-1,L,R),sp(L,l-k-1,L,M);
27     while(siz[M]<r-l+1)mg(M,M,M,1);
28     sp(M,r-l+1,M,M2),sp(u,r,L,R),sp(L,l-1,L,M2);
29     mg(L,L,M,1),mg(u,L,R,1);
30 }
31 void upd2(int& u,int v,int l,int r) {
32     int L,M,R,M2;
33     sp(v,r,L,R),sp(L,l-1,L,M);
34     sp(u,r,L,R),sp(L,l-1,L,M2);
35     mg(L,L,M),mg(u,L,R);
36 }
37 ll qry(int& u,int l,int r) {
38     int L,M,R;
39     sp(u,r,L,R),sp(L,l-1,L,M);
40     ll ret=sum[M];
41     mg(L,L,M),mg(u,L,R);
42     return ret;
43 }
44 void dfs(int u) {if(!u)return; dfs(l(u)),q[nq++]=val[u],dfs(r(u));}
45 void build(int& u,int l=0,int r=n-1) {
46     if(l>r) {u=0; return;}
47     int mid=(l+r)>>1;
48     u=newnode(q[mid]);
49     build(l(u),l,mid-1),build(r(u),mid+1,r),pu(u);
50 }
51 void rebuild() {tot=siz[A],nq=0,dfs(rt),build(rt);}
52 int main() {
53     srand(time(0));
54     scanf("%d%d",&n,&m);
55     for(int i=0; i<n; ++i)scanf("%d",&q[i]);
56     build(A),rt=A;
57     while(m--) {
58         int f,l,r,k;
59         scanf("%d%d%d",&f,&l,&r),l,r;
60         if(f==2)scanf("%d",&k);
61         if(f==1)printf("%lld\n",qry(rt,l,r));
62         else if(f==2)upd(rt,l,r,k);
63         else if(f==3)upd2(rt,A,l,r);
64         if(tot>2500000)rebuild();
65     }
66     return 0;
67 }

 

posted @ 2019-06-27 16:15  jrltx  阅读(602)  评论(0编辑  收藏  举报