博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

BZOJ.2002.Bounce 弹飞绵羊(LCT)

题目链接

从一个点只能往后跳,即后继状态只有一个,那么拿nxt[x]做fa[x]啊!这样就成了一棵树,从每个点开始的答案是它到所在树的根节点的距离。
nxt[]的更改即动态修改树边,用LCT即可。
这样查询需要的就是 Access(x),Splay(x);return sz[x];(sz[lson]+1一样...)
修改就将Cut(x,fa[x]),将x旋到根后砍掉左子树就行了。
因为不需要去查一条x->y的链,且保证是一棵树,所以Split,Make_root,PushDown...就可以省了。

//6292kb	1292ms
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
const int N=2e5+5;

int n,A[N],nxt[N];
inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-'0',c=gc());
	return now;
}
namespace LCT
{
	#define lson son[x][0]
	#define rson son[x][1]

	int fa[N],son[N][2],sz[N],sk[N];
	inline void Update(int x){
		sz[x]=sz[lson]+sz[rson]+1;
	}
	inline bool n_root(int x){
		return son[fa[x]][0]==x||son[fa[x]][1]==x;
	}
	void Rotate(int x)
	{
		int a=fa[x],b=fa[a],l=son[a][1]==x,r=l^1;
		if(n_root(a)) son[b][son[b][1]==a]=x;
		if(son[x][r]) fa[son[x][r]]=a;
		fa[a]=x, fa[x]=b;
		son[a][l]=son[x][r], son[x][r]=a;
		Update(a);//Update(x);
	}
	void Splay(int x)
	{
		int t=1,a=x,b; sk[1]=x;
		while(n_root(x))
		{
			a=fa[x], b=fa[a];
			if(n_root(a)) Rotate(son[a][1]==x^son[b][1]==a?x:a);
			Rotate(x);
		}
		Update(x);
	}
	void Access(int x){
		for(int pre=0; x; x=fa[pre=x])
			Splay(x), rson=pre, Update(x);
	}
	int Query(int x){
		Access(x),Splay(x); return sz[x];
	}
	void Modify(int x,int y){
//		Access(x), fa[x]=son[fa[x]][1]=0;//这样不对 x的左子树(可能有)还是连在fa[x]上的 
		Access(x), Splay(x), lson=fa[lson]=0, Update(x);
		if(x+y<=n) fa[x]=x+y;
	}
}

int main()
{
	n=read();
	for(int a,i=1; i<=n; ++i)
	{
		a=read(), LCT::sz[i]=1;
		if(i+a<=n) LCT::fa[i]=i+a;//不需要初始时都Link()起来,连轻边即可 
	}
	int opt,x,y,m=read();
	while(m--)
	{
		opt=read(),x=read()+1;
		if(opt==1) printf("%d\n",LCT::Query(x));
		else y=read(), LCT::Modify(x,y);
	}
	return 0;
}
posted @ 2018-03-21 15:25  SovietPower  阅读(222)  评论(0编辑  收藏  举报