【洛谷P3203】[HNOI2010]弹飞绵羊【LCT】

传送门

Solution

我们把一次从\(i\)向后弹到\(i+k_i\)看作是连了一条边,如果\(i+k_i>n\)也就是被弹飞了,我们就认为被弹到了一个特殊节点\(n+1\)

于是就直接维护\(Splay\)上子树的\(siz\),查询从\(x\)起步,就拉出从\(x\)\(n+1\)\(Splay\),将\(n+1\)置为根,然后输出\(n+1\)维护的\(siz\)即可

更改弹力系数就是先\(cut\)\(link\)

Code

#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
int n,siz[N],ch[N][2],fa[N],rev[N];
inline bool which(int x){return ch[fa[x]][1]==x;}
inline void pushup(int x){
	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
inline void rever(int x){
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}
inline void pushdown(int x){
	if(!rev[x]) return ;
	if(ch[x][0]) rever(ch[x][0]);
	if(ch[x][1]) rever(ch[x][1]);
	rev[x]=0;
}
inline void Rotate(int x){
	int y=fa[x],z=fa[y],wx=which(x),wy=which(y);
	if(!isroot(y)) ch[z][wy]=x;fa[x]=z;
	ch[y][wx]=ch[x][wx^1];
	if(ch[y][wx]) fa[ch[y][wx]]=y;
	ch[x][wx^1]=y;fa[y]=x;
	pushup(y);
}
int stk[N],top;
inline void Splay(int x){
	int now=x;
	stk[top=1]=now;
	while(!isroot(now)) now=fa[now],stk[++top]=now;
	while(top) pushdown(stk[top--]);
	while(!isroot(x)){
		int y=fa[x];
		if(!isroot(y)){
			if(which(x)==which(y)) Rotate(y);
			else Rotate(x);
		}Rotate(x);
	}
	pushup(x); 
} 
inline void access(int x){
	for(int last=0;x;last=x,x=fa[x])
		Splay(x),ch[x][1]=last,pushup(x);
}
inline void makeroot(int x){
	access(x);Splay(x);
	rever(x);
}
inline int findroot(int x){
	access(x);Splay(x);
	while(ch[x][0]) pushdown(x),x=ch[x][0];
	Splay(x);
	return x;
}
inline void split(int x,int y){
	makeroot(x);access(y);
	Splay(y);
}
inline void link(int x,int y){
	makeroot(x);
	fa[x]=y;
}
inline void cut(int x,int y){
	split(x,y);
	fa[x]=ch[y][0]=0;
	pushup(y);
}
int v[N],m,cnt=0;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&v[i]);
		v[i]+=i;
		if(v[i]>n) v[i]=n+1;
		link(i,v[i]);
	}
	scanf("%d",&m);
	for(int i=1;i<=m;++i){
		int op,x,y;
		scanf("%d%d",&op,&x);++x;
		if(op==1){
			split(x,n+1);
			printf("%d\n",siz[n+1]-1); 
		}
		else{
			scanf("%d",&y);
			int nw=y+x;if(nw>n) nw=n+1;
			if(nw==v[x]) continue;
			else cut(x,v[x]),v[x]=nw,link(x,v[x]);
		}
	} 
	return 0;
}
posted @ 2021-01-06 20:09  cjTQX  阅读(75)  评论(0编辑  收藏  举报