20200727 T3 小w维护序列【平衡树预留插入位置+三维数点】

题目描述

在这里插入图片描述
在这里插入图片描述

题目分析

先考虑没有插入删除的情况。

区间不同的数有个常见的 trick 是把它表示为二维的点 ( p r e i , i ) (pre_i,i) (prei,i),区间查询就变成数第一维在 [ 0 , l − 1 ] [0,l-1] [0,l1],第二维在 [ 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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值