P5350 序列 可持久化fhq
题意:
分析:
- 前置芝士: 可持久化文艺平衡树
我们发现 \(1,2,3,6\) 这些操作就是 \(fhq\) 的基操,模板题做过就会
所以我们只需要考虑 \(4,5\) 操作
对于 \(5\) 操作就直接裂成 \(5\) 段,然后交换第 \(2\) 和 \(4\) 段,再合上就好了
对于 \(4\) 操作,我们发现因为 \(fhq\) 不支持插入一段区间,只能一个元素一个元素并上去,那么复杂度就会变成 \(O(qn)\) ,所以我们需要记一下历史版本,然后直接复制历史版本的元素信息到对应的位置上,这样就相当于加上了一段区间
然后你就会得到 \(MLE\) 的好成绩,做了 可持久化\(fhq\)/可持久化文艺平衡树 就会发现,这道题的空间小的离谱,只有 \(128M\) 也就是说我们不可能把所有的历史版本都存下来,那么只能在空间达到一定程度后重构 \(fhq\) 把所有 \(4\) 操作带来的影响加上去,来维持空间复杂度,具体来说就是遍历整个 \(fhq\) 把所有标记都清除后重建一个 \(fhq\)
tip:
对于可持久化 \(fhq\) ,需要在任何改变平衡树形态和元素信息的地方记录一下历史版本,比如 \(pushdown,merge,split\) 的时候
代码:
这应该是我写过的最长的数据结构题,足足 \(7k\) 代码
#include<bits/stdc++.h>
using namespace std;
namespace zzc
{
#define getchar() (tt == ss && (tt = (ss = In) + fread(In, 1, 1 << 20, stdin), ss == tt) ? EOF : *ss++)
char In[1 << 20], *ss=In, *tt=In;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn = 3e6+5;
const int mod = 1e9+7;
int n,m,num;
int tmp[maxn];
namespace fhq_treap
{
int cnt,rt;
struct node
{
int lc,rc,sum,val,siz,rnd,add,tag,rev;
}t[maxn];
inline int new_node(int x=0)
{
int u=++cnt;
t[u].val=t[u].sum=x;
t[u].siz=1;
t[u].tag=-1;
t[u].add=0;
t[u].rnd=rand();
return u;
}
inline int copy(int x)
{
int u=++cnt;
t[u]=t[x];return u;
}
inline void pushup(int x)
{
t[x].siz=t[t[x].lc].siz+t[t[x].rc].siz+1;
t[x].sum=((t[t[x].lc].sum+t[t[x].rc].sum)%mod+t[x].val)%mod;
}
inline void push_tag(int x,int k)
{
t[x].add=0;
t[x].tag=t[x].val=k;
t[x].sum=1ll*t[x].siz*k%mod;
}
inline void push_add(int x,int k)
{
t[x].add=(t[x].add+k)%mod;
t[x].val=(t[x].val+k)%mod;
t[x].sum=(1ll*t[x].sum+1ll*t[x].siz*k)%mod;
}
inline void push_rev(int x)
{
swap(t[x].lc,t[x].rc);
t[x].rev^=1;
}
inline void pushdown(int x)
{
if(!t[x].rev&&!t[x].add&&t[x].tag==-1) return ;
if(t[x].lc) t[x].lc=copy(t[x].lc);
if(t[x].rc) t[x].rc=copy(t[x].rc);
if(t[x].tag!=-1)
{
if(t[x].lc) push_tag(t[x].lc,t[x].tag);
if(t[x].rc) push_tag(t[x].rc,t[x].tag);
t[x].tag=-1;
}
if(t[x].add)
{
if(t[x].lc) push_add(t[x].lc,t[x].add);
if(t[x].rc) push_add(t[x].rc,t[x].add);
t[x].add=0;
}
if(t[x].rev)
{
if(t[x].lc) push_rev(t[x].lc);
if(t[x].rc) push_rev(t[x].rc);
t[x].rev=0;
}
}
int merge(int x,int y)
{
if(!x||!y) return x|y;
if(t[x].rnd<t[y].rnd)
{
pushdown(x);x=copy(x);
t[x].rc=merge(t[x].rc,y);
pushup(x);return x;
}
else
{
pushdown(y);y=copy(y);
t[y].lc=merge(x,t[y].lc);
pushup(y);return y;
}
}
void split(int tmp,int k,int &u,int &v)
{
if(!tmp)
{
u=0;v=0;
return ;
}
pushdown(tmp);
if(t[t[tmp].lc].siz<k)
{
u=copy(tmp);
split(t[u].rc,k-t[t[tmp].lc].siz-1,t[u].rc,v);
pushup(u);
}
else
{
v=copy(tmp);
split(t[v].lc,k,u,t[v].lc);
pushup(v);
}
}
inline void modify(int l,int r,int k)
{
int x,y,z;
split(rt,r,x,z);
split(x,l-1,x,y);
y=copy(y);
push_tag(y,k);
rt=merge(x,merge(y,z));
}
inline void update(int l,int r,int k)
{
int x,y,z;
split(rt,r,x,z);
split(x,l-1,x,y);
y=copy(y);
push_add(y,k);
rt=merge(x,merge(y,z));
}
inline void query(int l,int r)
{
int x,y,z;
split(rt,r,x,z);
split(x,l-1,x,y);
printf("%d\n",t[y].sum%mod);
rt=merge(x,merge(y,z));
}
inline void paste(int l1,int r1,int l2,int r2)
{
int a,b,c,d,e;
bool flag=false;
if(l1>l2)
{
swap(l1,l2);
swap(r1,r2);
flag=true;
}
split(rt,r2,d,e);
split(d,l2-1,c,d);
split(c,r1,b,c);
split(b,l1-1,a,b);
if(flag) b=copy(d);
else d=copy(b);
rt=merge(a,merge(b,merge(c,merge(d,e))));
}
inline void _swap(int l1,int r1,int l2,int r2)
{
int a,b,c,d,e;
if(l1>l2)
{
swap(l1,l2);
swap(r1,r2);
}
split(rt,r2,d,e);
split(d,l2-1,c,d);
split(c,r1,b,c);
split(b,l1-1,a,b);
rt=merge(a,merge(d,merge(c,merge(b,e))));
}
inline void reverse(int l,int r)
{
int x,y,z;
split(rt,r,x,z);
split(x,l-1,x,y);
y=copy(y);
push_rev(y);
rt=merge(x,merge(y,z));
}
void dfs(int const &x)
{
pushdown(x);
if(t[x].lc) dfs(t[x].lc);
tmp[++num]=t[x].val;
if(t[x].rc) dfs(t[x].rc);
}
int build(int l,int r)
{
if(l>r) return 0;
int mid=(l+r)>>1;
int x=new_node(tmp[mid]);
t[x].lc=build(l,mid-1);
t[x].rc=build(mid+1,r);
pushup(x);
return x;
}
inline void rebuild()
{
num=0;dfs(rt);cnt=0;
rt=build(1,num);
}
void watch()
{
int x,y,z;
for(int i=1;i<=n;i++)
{
split(rt,i,x,z);
split(x,i-1,x,y);
printf("%d ",t[y].val);
rt=merge(x,merge(y,z));
}
puts("");
}
}
using namespace fhq_treap;
void work()
{
srand(time(0));
int opt,l1,l2,r1,r2,v;
n=read();m=read();
for(int i=1;i<=n;i++) tmp[i]=read();
rt=build(1,n);
for(int i=1;i<=m;i++)
{
opt=read();l1=read();r1=read();
switch(opt)
{
case 1:
{
query(l1,r1);
break;
}
case 2:
{
v=read();
modify(l1,r1,v);
break;
}
case 3:
{
v=read();
update(l1,r1,v);
break;
}
case 4:
{
l2=read();r2=read();
paste(l1,r1,l2,r2);
break;
}
case 5:
{
l2=read();r2=read();
_swap(l1,r1,l2,r2);
break;
}
case 6:
{
reverse(l1,r1);
break;
}
}
if(cnt>2000000) rebuild();
//printf("%d : ",i);watch();
}
num=0;dfs(rt);
for(int i=1;i<=n;i++) printf("%d ",tmp[i]);
}
}
int main()
{
zzc::work();
return 0;
}