牛客小白月赛18 E.Forsaken的数列【Splay】

时间:2020-04-13
本文章向大家介绍牛客小白月赛18 E.Forsaken的数列【Splay】,主要包括牛客小白月赛18 E.Forsaken的数列【Splay】使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

传送门
之前用 FhqTreap 写过,刚刚学了 splay,再用 splay 写一下。
splay 比 FhqTreap 好的地方就是好写一点,但速度丢人。
splay 处理区间问题,就每次将代表 l-1 位置的点甩到根,然后将代表 r+1 的点甩到根的右儿子,那么此时 r+1 的点的左子树就是要处理的区间。
在指定位置插入数也是一个道理,将 pos-1 甩到根,pos 甩到根的右儿子,把新插入的点设为 pos 的左儿子即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+10;
int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
	return x*f;
}
int n,a[N];

struct Splay{
	int root,siz[N],fa[N],ch[N][2],tot;LL sum[N],val[N],tag[N];
	int newnode(int x,int f){fa[++tot]=f;val[tot]=sum[tot]=x;siz[tot]=1;return tot;}
	int relat(int p,int f){return ch[f][1]==p;}
	void connect(int p,int f,int k){ch[f][k]=p;fa[p]=f;}
	void pushup(int p){
		siz[p]=siz[ch[p][0]]+siz[ch[p][1]]+1;
		sum[p]=sum[ch[p][0]]+sum[ch[p][1]]+val[p];
	}
	void pushdown(int id){
		int ls=ch[id][0],rs=ch[id][1];
		sum[ls]+=tag[id]*siz[ls];val[ls]+=tag[id];tag[ls]+=tag[id];
		sum[rs]+=tag[id]*siz[rs];val[rs]+=tag[id];tag[rs]+=tag[id];
		tag[id]=0;
	}
	void rotate(int p){
		int f=fa[p],ff=fa[f],k=relat(p,f);
		connect(ch[p][k^1],f,k);
		connect(p,ff,relat(f,ff));
		connect(f,p,k^1);
		pushup(f);pushup(p);
	}
	void splay(int p,int top){
		if(top==0) root=p;
		while(fa[p]!=top){
			int f=fa[p],ff=fa[f];
			if(ff!=top) relat(p,f)^relat(f,ff)?rotate(p):rotate(f);
			rotate(p);
		}
	}
	int findpos(int k){
		int p=root;
		while(1){
			if(tag[p]) pushdown(p);
			if(k<=siz[ch[p][0]]) p=ch[p][0];
			else if(k==siz[ch[p][0]]+1) break;
			else k-=siz[ch[p][0]]+1,p=ch[p][1];
		}
		return p;
	}
	void insert(int k,int x=0){
		int p=findpos(k),q=findpos(k+1);
		splay(p,0);splay(q,p);
		int id=newnode(x,q);
		ch[q][0]=id;
		splay(id,0);
	}
	void upd(int l,int r,int x){
		int p=findpos(l),q=findpos(r+2);
		splay(p,0);splay(q,p);
		int id=ch[q][0];
		sum[id]+=1ll*x*siz[id];val[id]+=x;tag[id]+=x;
	}
	LL ask(int l,int r){
		int p=findpos(l),q=findpos(r+2);
		splay(p,0);splay(q,p);
		return sum[ch[q][0]];
	}
}spl;

int main(){
	n=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=0;i<=n+1;i++){
		int p=spl.newnode(a[i],i);
		if(i) spl.ch[i][1]=p;
		spl.splay(p,0);
	}
	int m=read();
	while(m--){
		int opt=read();
		if(opt==1) {int pos=read();spl.insert(pos);}
		else if(opt==2){
			int l=read(),r=read(),x=read();
			spl.upd(l,r,x);
		}
		else if(opt==3){
			int l=read(),r=read();
			printf("%lld\n",spl.ask(l,r));
		}
	}
	return 0;
}

原文地址:https://www.cnblogs.com/BakaCirno/p/12691934.html