题目描述
题目分析
先考虑没有插入删除的情况。
区间不同的数有个常见的 trick 是把它表示为二维的点
(
p
r
e
i
,
i
)
(pre_i,i)
(prei,i),区间查询就变成数第一维在
[
0
,
l
−
1
]
[0,l-1]
[0,l−1],第二维在
[
l
,
r
]
[l,r]
[l,r] 的点。
修改就是去掉原来的点,加入新的点,可以用 map 套 set 维护。(离散化好麻烦,复杂度也没区别)
询问一也可以通过简单的处理把不同点之间的贡献分离开:
那么这就是一个三维数点问题,cdq分治即可。(学到一个树状数组套树状数组解决三维数点的方法:按第一维排序,第二维把询问和修改分别放到第一个树状数组的 vector 里(就跟普通树状数组的实现方式类似),然后取出每个 vector,用树状数组求第三维的区间和,这样空间是 nlogn 的,常数、码量都很小。)
然后考虑怎么删除插入:
主要的问题是它们会改变序列的结构。我们可以用离线操作,用平衡树预处理,把要插入的节点位置给它预留出来,并找到所有询问和修改在新的序列上对应的位置。
在处理到当前操作时,要找到询问或修改位置在平衡树上对应的点,在平衡树插入删除结束后,只要按中序遍历遍历平衡树,就可以知道对应点在新序列中的位置。
有个注意的点是删除操作不能在平衡树中将它删去(要保留它的位置),但是又不能影响后面找排名为某某的位置,可以将它的权值设为 0,而其它存在的点的权值设为 1,查找对应位置时就去找对应的权值为 1 的点,而避开权值为 0 的点即可。
Code:
#include<bits/stdc++.h>
#define maxn 200005
using namespace std;
char cb[1<<20],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<20,stdin),cs==ct)?0:*cs++)
void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
const int mod = 1e9+7, inv6 = 166666668;
int n,m,A[maxn],B[maxn],pos[maxn],tim;
int OP[maxn],X[maxn],Y[maxn];
namespace Treap{
int rt,lc[maxn],rc[maxn],siz[maxn],live[maxn],rnd[maxn],tot;
int New(){return rnd[++tot]=rand(),siz[tot]=live[tot]=1,tot;}
void upd(int i){siz[i]=siz[lc[i]]+siz[rc[i]]+live[i];}
void merge(int &t,int a,int b){
if(!a||!b) return void(t=a+b);
if(rnd[a]<rnd[b]) t=a,merge(rc[t],rc[a],b);
else t=b,merge(lc[t],a,lc[b]);
upd(t);
}
void split0(int t,int &a,int &b,int k){
if(!t) return void(a=b=0);
if(k>=siz[lc[t]]+live[t]) a=t,split0(rc[t],rc[a],b,k-siz[lc[t]]-live[t]);
else b=t,split0(lc[t],a,lc[b],k);
upd(t);
}
void split1(int t,int &a,int &b){
if(siz[lc[t]]) b=t,split1(lc[t],a,lc[b]);
else a=t,b=rc[t],rc[t]=0;
}
int a,b,c;
int find(int k){
split0(rt,a,b,k-1),split1(b,c,b),merge(b,c,b),merge(rt,a,b);
return c;
}
int del(int k){
split0(rt,a,b,k-1),split1(b,c,b),siz[c]=live[c]=0,merge(b,c,b),merge(rt,a,b);
return c;
}
int ins(int k){
split0(rt,a,b,k),merge(a,a,New()),merge(rt,a,b);
return tot;
}
void dfs(int i){
if(!i) return;
dfs(lc[i]),pos[i]=++tim,dfs(rc[i]);
}
}
using namespace Treap;
map<int,set<int>>mp;
set<int>::iterator it,pre,nxt;
struct node{
int x,y,v,t,id;
bool operator < (const node &p)const{return x<p.x;}
}q[maxn*3];
int cnt,ans[maxn][4];
void Ins(int i){
int x=X[i],y=B[x];
pre=nxt=it=mp[y].insert(x).first;
int l=pre==mp[y].begin()?0:*--pre, r=++nxt==mp[y].end()?tim+1:*nxt;
q[++cnt]=(node){l,x,y,1,i};
if(r<=tim) q[++cnt]=(node){l,r,B[r],-1,i},q[++cnt]=(node){x,r,B[r],1,i};
}
void Del(int i){
int x=X[i],y=B[x];
pre=nxt=it=mp[y].lower_bound(x);
int l=pre==mp[y].begin()?0:*--pre, r=++nxt==mp[y].end()?tim+1:*nxt;
q[++cnt]=(node){l,x,y,-1,i};
if(r<=tim) q[++cnt]=(node){x,r,B[r],-1,i},q[++cnt]=(node){l,r,B[r],1,i};
mp[y].erase(it);
}
int arr[maxn][4],vis[maxn],idx;
void upd(int i,int v,int tp){
int s[4]={tp,v*tp,int(1ll*tp*v*v%mod),int(1ll*tp*v*v%mod*v%mod)};
for(;i<=tim;i+=i&-i){
if(vis[i]!=idx) {memset(arr[i],0,sizeof arr[i]),vis[i]=idx;}
arr[i][0]+=s[0],(arr[i][1]+=s[1])%=mod,(arr[i][2]+=s[2])%=mod,(arr[i][3]+=s[3])%=mod;
}
}
void qry(int *ans,int tp,int i,int op){
if(op==-5){
for(;i;i-=i&-i) if(vis[i]==idx) ans[0]+=tp*arr[i][0];
}
else{
for(;i;i-=i&-i) if(vis[i]==idx) (ans[1]+=tp*arr[i][1])%=mod,(ans[2]+=tp*arr[i][2])%=mod,(ans[3]+=tp*arr[i][3])%=mod;
}
}
void solve(int l,int r,int ql,int qr){
if(l>=r||ql>=qr) return;
int mid=(l+r)>>1,pos;
for(int i=ql;i<=qr;i++) if(q[i].id<=mid) pos=i;
solve(l,mid,ql,pos),solve(mid+1,r,pos+1,qr);
stable_sort(q+ql,q+qr+1),++idx;
for(int i=ql;i<=qr;i++)
if(q[i].id<=mid) {if(q[i].v>=1) upd(q[i].y,q[i].v,q[i].t);}
else {if(q[i].v<0) qry(ans[q[i].id],q[i].t,q[i].y,q[i].v);}
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;i++) read(A[i]),merge(rt,rt,New());
for(int i=1;i<=m;i++){
read(OP[i]),read(X[i]),OP[i]!=3&&(read(Y[i]),0);
if(OP[i]==1) X[i]=find(X[i]),Y[i]=find(Y[i]);
if(OP[i]==2) X[i]=find(X[i]);
if(OP[i]==3) X[i]=del(X[i]);
if(OP[i]==4) X[i]=ins(X[i]);
if(OP[i]==5) X[i]=find(X[i]),Y[i]=find(Y[i]);
}
dfs(rt);
for(int i=1;i<=n;i++){
it = mp[A[i]].insert(pos[i]).first;
q[++cnt]=(node){it==mp[A[i]].begin()?0:*--it,pos[i],A[i],1,0};
B[pos[i]]=A[i];
}
for(int i=1;i<=m;i++){
X[i]=pos[X[i]]; if(OP[i]==1||OP[i]==5) Y[i]=pos[Y[i]];
if(OP[i]==1) q[++cnt]=(node){X[i]-1,Y[i],-1,1,i},q[++cnt]=(node){X[i]-1,X[i]-1,-1,-1,i};
if(OP[i]==2) Del(i),B[X[i]]=Y[i],Ins(i);
if(OP[i]==3) Del(i),B[X[i]]=0;
if(OP[i]==4) B[X[i]]=Y[i],Ins(i);
if(OP[i]==5) q[++cnt]=(node){X[i]-1,Y[i],-5,1,i},q[++cnt]=(node){X[i]-1,X[i]-1,-5,-1,i};
}
solve(0,m,1,cnt);
for(int i=1;i<=m;i++)
if(OP[i]==5) printf("%d\n",ans[i][0]);
else if(OP[i]==1) printf("%d\n",((1ll*ans[i][1]*ans[i][1]%mod*ans[i][1]-3ll*ans[i][2]*ans[i][1]+2*ans[i][3])%mod+mod)*inv6%mod);
}