ARC030D グラフではない
difficulty 3246
题意:给出序列 \(A\),你需要进行三种操作:
- 区间加
- 给定两个长度相同的区间 \([a,b] ,[c,d]\),你需要用 \([c,d]\) 位置的数依次覆盖 \([a,b]\) 位置中的数。
- 区间求和
序列可能会爆 long long,长度不超过 2e5.
这是一道卡常卡空间的 3200 板子题,非常不推荐。
考虑建出 FHQ Treap,然后可以对每个节点维护加法 tag,并在区间覆盖的时候相应地 pushdown 和 pushup。
此处为了谨慎,建议在 merge 和 split 中频繁 pushdown。
接下来是本题的难点:需要在 split 中对每个根节点建一个副本,满足从该副本往下可以得到 split 之前的树的形态,这其实是一种可持久化思想,但本题中只需要持久化一步,所以实现较为容易,注意简单的细节问题即可。
但是这样仍然不优秀,我们发现这个 750 MB 的空间卡死了,并且如果你使用一般的垃圾回收你会发现它与可持久化是不能兼容的(拷贝副本后应当保留原来的节点,但是我们会自动把它回收掉),为了达到兼容的目的我们需要一些特判。
也有更简单的思路,即设置一个阈值,当节点个数超过阈值时默认为垃圾太多,对整棵树进行重构,这个阈值在本题中对复杂度没有什么影响,因为可以把它选的很大,例如 10^7.
这样总时间复杂度是 \(O(n \log n)\) 的,常数非常大。
#include<bits/stdc++.h>
#define N 40000005
#define ll long long
#define ls(x) (ch[x][0])
#define rs(x) (ch[x][1])
#define M 1000000007
#define pb push_back
using namespace std;
int ch[N][2],key[N],cn,sz[N];
ll sum[N],add[N],val[N],A[N];
int rnd(){return (int)(1ll*rand()*rand()%M+1);}
void pushup(int x){
sum[x]=sum[ls(x)]+sum[rs(x)]+1ll*val[x];
sz[x]=sz[ls(x)]+sz[rs(x)]+1;
}void cl(int x){
ch[x][0]=ch[x][1]=sz[x]=add[x]=val[x]=0;
sum[x]=key[x]=0;
}void cpy(int rt,int u){
ch[rt][0]=ch[u][0],ch[rt][1]=ch[u][1];
key[rt]=key[u],sz[rt]=sz[u],sum[rt]=sum[u];
add[rt]=add[u],val[rt]=val[u];
}int getN(){return ++cn;}
int New(ll v){
int x=getN(); ch[x][0]=ch[x][1]=0;
sz[x]=1,add[x]=0,sum[x]=val[x]=v,key[x]=rnd(); return x;
}void grt(int &rt){int u=rt; rt=getN(),cpy(rt,u);}
void upd(int &rt,ll d){
grt(rt),sum[rt]+=1ll*d*sz[rt];
val[rt]+=1ll*d,add[rt]+=1ll*d;
}void pd(int &rt){
grt(rt); if(ls(rt)) upd(ls(rt),add[rt]);
if(rs(rt)) upd(rs(rt),add[rt]);
add[rt]=0; return;
}int mer(int x,int y){
if(!x||!y) return x+y; int ret=0;
if(key[x]<key[y]) pd(y),ls(y)=mer(x,ls(y)),pushup(y),ret=y;
else pd(x),rs(x)=mer(rs(x),y),pushup(x),ret=x; return ret;
}void splt(int rt,int &a,int &b,int v){
if(!rt){a=b=0; return;} pd(rt);
if(sz[ls(rt)]>=v) b=rt,splt(ls(rt),a,ls(rt),v);
else a=rt,splt(rs(rt),rs(rt),b,v-sz[ls(rt)]-1); pushup(rt);
}int n,Q,n1=0,B=12000000;
void init(int &rt){
rt=cn=0,srand(time(0));
for(int i=1;i<=n;i++) rt=mer(rt,New(A[i]));
}void dfs(int &rt){
pd(rt); if(ls(rt)) dfs(ls(rt));
A[++n1]=val[rt];
if(rs(rt)) dfs(rs(rt)); pushup(rt);
}signed main(){
scanf("%d%d",&n,&Q); int rt;
for(int i=1;i<=n;i++) scanf("%lld",&A[i]); init(rt);
while(Q--){
int a,b,c,d,op,v,p,q,r,s,t,u;
scanf("%d%d%d",&op,&a,&b);
if(op==1){
scanf("%d",&v);
splt(rt,p,q,b),splt(p,p,r,a-1);
upd(r,v),rt=mer(p,mer(r,q));
}if(op==2){
scanf("%d%d",&c,&d);
splt(rt,p,q,d),splt(p,p,r,c-1);
splt(rt,s,t,b),splt(s,s,u,a-1);
rt=mer(mer(s,r),t);
}if(op==3){
splt(rt,p,q,b),splt(p,p,r,a-1);
printf("%lld\n",sum[r]);
rt=mer(mer(p,r),q);
}if(cn>=B) n1=0,dfs(rt),init(rt);
}return 0;
}

浙公网安备 33010602011771号