splay

奇怪的码长增加了

魔板

bool Type(int x) {return x==son[fa[x]][1];}
void Update(int x) {size[x]=cnt[x]+size[son[x][0]]+size[son[x][1]];}
void change(int x) {
	int y=fa[x],z=fa[y],k=Type(x);
	fa[x]=z;
	if(z) son[z][Type(y)]=x; else fa[x]=0;
	son[y][k]=son[x][k^1];
	fa[son[y][k]]=y;
	son[x][k^1]=y;
	fa[y]=x;
	Update(y),Update(x);
}
void splay(int x) {
	for(int f=fa[x];f=fa[x];change(x)) {
		if(fa[f]) change(Type(x)==Type(f)?f:x);
	}
	root=x;
}
void init(int val) {
	tot++;
	data[tot]=val,fa[tot]=0,size[tot]=cnt[tot]=1,root=tot;
}

void Insert(int val) {
	if(!tot) {init(val);return;}
	tot++;
	int p=root; bool flag=0;
	while(p) {
		size[p]++;
		if(val==data[p]) {
			flag=1;cnt[p]++;tot--; break;
		}
		else if(val<data[p]) {
			if(son[p][0]) p=son[p][0];
			else {son[p][0]=tot;break;}
		}
		else {
			if(son[p][1]) p=son[p][1];
			else {son[p][1]=tot;break;}
		}
	}
	if(!flag) {
		fa[tot]=p;data[tot]=val,cnt[tot]=size[tot]=1;
		splay(tot);
//		printf("!%d %d %d\n",tot,cnt[tot],size[tot]);
	}
	else splay(p);
}
int fd_kth(int k) {
	int p=root;
	while(p) {
//		printf("(%d)%d %d\n",data[p],data[son[p][1]],k);
		if(size[son[p][1]]+1<=k&&size[son[p][1]]+cnt[p]>=k) break;
		if(size[son[p][1]]+1>k) {p=son[p][1];}
		else {k-=size[son[p][1]]+cnt[p];p=son[p][0];}
	}
	return data[p];
}
int Find(int val) {
	int p=root;
	while(p) {
		if(data[p]==val) return p;
		if(data[p]<val) p=son[p][1];
		else p=son[p][0];
	}
	return 0;
}

当然,很多时候跟区间相关的题目会用到一种操作,如\([L,R]\),\(x=fd(L-1),y=fd(R+1)\),\(splay(x,0),splay(y,x)\)然后我们把区间\([L,R]\)卡成了\(son[y][0]\)的子树,然后操作就对该子树即可

区间翻转问题

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
bool Lazy[N];
int a[N],fa[N],root,son[N][2],val[N],sum[N],mx[N],size[N],tot;
void P_up(int u) {	//xxxx
	int ls=son[u][0],rs=son[u][1];
	sum[u]=val[u]+sum[ls]+sum[rs];
	mx[u]=max(val[u],max(mx[ls],mx[rs]));
	size[u]=1+size[ls]+size[rs];
}
void P_dw(int u) {
	if(!Lazy[u])return;
	swap(son[u][0],son[u][1]);
	Lazy[son[u][0]]^=1,Lazy[son[u][1]]^=1;
	Lazy[u]=0;
}
int Build(int l,int r) {		//????????
	if(l>r)return 0;
	int mid=(l+r)>>1;
	int u=++tot;
	size[u]=1,val[u]=sum[u]=mx[u]=a[mid];
	son[u][0]=Build(l,mid-1),son[u][1]=Build(mid+1,r);
	fa[son[u][0]]=u,fa[son[u][1]]=u;
	P_up(u);
	return u;
}
bool Type(int x) {return x==son[fa[x]][1];}
void change(int x) {
	int y=fa[x],z=fa[y],k=Type(x);
	fa[x]=z;
	if(z) son[z][Type(y)]=x; else root=x;
	son[y][k]=son[x][k^1];
	fa[son[y][k]]=y;
	son[x][k^1]=y;
	fa[y]=x;
	P_up(y),P_up(x);
}
void splay(int x,int y) {
	for(int f=fa[x];f=fa[x],f!=y;change(x)) {
		if(fa[f]!=y) change(Type(x)==Type(f)?f:x);
	}
	if(!y) root=x;
}
int fd_kth(int k) {
	int p=root;
	while(p) {
		P_dw(p);
		int ls=son[p][0];
		if(size[ls]+1==k) break;
		else if(size[ls]+1<k) {k-=size[ls]+1;p=son[p][1];}
		else p=son[p][0];
	}
	return p;
}
int Query(int l,int r,int opt) {
	int x=fd_kth(l-1),y=fd_kth(r+1);
	splay(x,0),splay(y,x);
	int k=son[y][0];
	if(!opt) return sum[k];
	else return mx[k];
}
void Update(int l,int r) {
	int x=fd_kth(l-1),y=fd_kth(r+1);
	splay(x,0),splay(y,x);
	int k=son[y][0];
	Lazy[k]^=1;
}
int main() {
	int n,m;
	scanf("%d%d",&n,&m);
	a[1]=a[n+2]=0;
	for(int i=1;i<=n;i++) {scanf("%d",&a[i+1]);}
	Build(1,n+2); root=1;
	for(int i=1;i<=m;i++) {
		int opt,k,d,l,r;
		scanf("%d",&opt);
		if(opt==1) {
			scanf("%d",&k);
			int p=fd_kth(k+1);
			splay(p,0);
			printf("%d\n",val[p]);
		}
		else if(opt==2) {
			scanf("%d%d",&k,&d);
			int p=fd_kth(k+1);
			val[p]+=d;
			splay(p,0);
		}
		else {
			scanf("%d%d",&l,&r); 
			l++;r++;
			if(opt==5) Update(l,r);
			else printf("%d\n",Query(l,r,opt-3));
		}
//		printf("?%d %d %d\n",root,son[root][0],son[root][1]);
	}
	return 0;
}
上一篇:小x玩游戏


下一篇:树上随机游走与树上高斯消元