BZOJ4764 弹飞大爷

14 篇文章 0 订阅

弹飞绵羊仙人掌版环套树版

lct维护动态环套树

考虑用和动态仙人掌一样的方法,给所有在环上的点都打一个环标记,值等于根的编号

这样的话在link和cut的时候各种特判然后维护环编号即可

判forever就是看根有没有环编号

注意换根之后把根换回原来的

注意cut根和根指向的环上点的情况

注意各种情况……

#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 200010
#define MAXM 1010
#define ll long long
#define eps 1e-8
#define MOD 1000000007
#define INF 1000000000
int fa[MAXN],son[MAXN][2],siz[MAXN],cir[MAXN],ch[MAXN];
int st[MAXN],tp;
bool rev[MAXN];
int n,m;
int a[MAXN];
inline void ud(int x){
	siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
}
inline void torev(int x){
	if(!x){
		return ;
	}
	swap(son[x][0],son[x][1]);
	rev[x]^=1;
}
inline void toch(int x,int y){
	if(!x){
		return ;
	}
	cir[x]=ch[x]=y;
}
inline void pd(int x){
	if(rev[x]){
		torev(son[x][0]);
		torev(son[x][1]);
		rev[x]=0;
	}
	if(ch[x]!=-1){
		toch(son[x][0],ch[x]);
		toch(son[x][1],ch[x]);
		ch[x]=-1;
	}
}
inline bool ir(int x){
	return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
inline void cot(int x,int y,bool z){
	if(x){
		fa[x]=y;
	}
	if(y){
		son[y][z]=x;
	}
}
inline void rot(int x,bool z){
	int xx=fa[x],xxx=fa[xx];
	cot(son[x][z],xx,z^1);
	if(ir(xx)){
		fa[x]=xxx;
	}else{
		cot(x,xxx,son[xxx][1]==xx);
	}
	cot(xx,x,z);
	ud(xx);
}
inline void apd(int x){
	int i;
	st[++tp]=x;
	for(i=x;!ir(i);i=fa[i]){
		st[++tp]=fa[i];
	}
	for(;tp;tp--){
		pd(st[tp]);
	}
}
void splay(int x){
	apd(x);
	while(!ir(x)){
		int xx=fa[x],xxx=fa[xx];
		if(ir(xx)){
			rot(x,son[xx][0]==x);
		}else{
			bool z=son[xxx][0]==xx;
			
			if(son[xx][z]==x){
				rot(x,z^1);
				rot(x,z);
			}else{
				rot(xx,z);
				rot(x,z);
			}
		}
	}
	ud(x);
}
void acs(int x){
	int t=0;
	while(x){
		splay(x);
		son[x][1]=t;
		ud(x);
		t=x;
		x=fa[x];
	}
}
inline void reboot(int x){
	acs(x);
	splay(x);
	torev(x);
}
inline void link(int x,int y){
	reboot(x);
	fa[x]=y;
}
inline void cut(int x,int y){
	reboot(x);
	acs(y);
	splay(y);
	son[y][0]=fa[x]=0;
	ud(y);
}
int rt(int x){
	acs(x);
	splay(x);
	pd(x);
	while(son[x][0]){
		x=son[x][0];
		pd(x);
	}
	return x;
}
void tolink(int x,int y){
	if(rt(x)==rt(y)){
		reboot(x);
		acs(y);
		splay(y);
		toch(y,x);
	}else{
		link(x,y);
	}
}
void tocut(int x,int y){
	acs(x);
	splay(x);
	int xx=cir[x];
	acs(y);
	splay(y);
	int yy=cir[y];
	int z=rt(x);
	if(cir[x]&&cir[x]==cir[y]){
		int zz=z+a[z];
		acs(zz);
		splay(zz);
		toch(zz,0);
		if(!(x==z&&y==zz)){
			cut(x,y);
			link(z,zz);
		}
	}else{
		cut(x,y);
		reboot(z);
	}
}
int main(){
	int i,o,x,y;
	memset(ch,-1,sizeof(ch));
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		siz[i]=1;
	}
	for(i=1;i<=n;i++){
		scanf("%d",&a[i]);
		if(i+a[i]>=1&&i+a[i]<=n&&a[i]){
			tolink(i,i+a[i]);
		}
	}
	while(m--){
		scanf("%d",&o);
		if(o==1){
			scanf("%d",&x);
			int y=rt(x);
			if(cir[y]){
				printf("-1\n");
			}else{
				if(!a[y]){
					printf("-1\n");
				}else{
					printf("%d\n",siz[x]);
				}
			}
			
		}else{
			scanf("%d%d",&x,&y);
			int xx=x+a[x];
			if(xx<1||xx>n||!a[x]){
				if(!a[x]){
					acs(x);
					splay(x);
					toch(x,0);
				}
				a[x]=y;
				if(x+a[x]>=1&&x+a[x]<=n){
					tolink(x,x+a[x]);
				}
			}else{
				tocut(x,xx);
				a[x]=y;
				if(x+a[x]>=1&&x+a[x]<=n){
					tolink(x,x+a[x]);
				}
			}
		}
	}
	return 0;
}
/*
2 3
-3 4
2 2 0
2 2 2
1 2

*/




评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值