【[HNOI2010]弹飞绵羊】LCT乱搞题

最近新学了LCT,又可以刷一堆水(keng)题了,真是开心啊

传送门:  https://www.luogu.org/problemnew/show/P3203

感觉还是很显然吧,直接将这个(点)与(点+劲度系数)的点连接起来,

同时考虑建一个空结点n+1(编号0不好处理,于是所有编号向上平移一个单位),意为所有的绵羊到这个地方就能够被弹飞

如果连接的时候i+k<=n就连不然就和n+1连接起来

每一次询问操作,setroot(x) access(n+1) splay(n+1),答案就是siz[n+1]-1

而每次进行修改劲度系数的时候,不只是光要连,还要将原来的边删掉。 就可以了(同时记得编号连接不大于n+1规定)

就这样搞定了,开始痛苦地调试罢!

cheer!

#include<bits/stdc++.h>
#define zig(x) zigzag(x,1)
#define zag(x) zigzag(x,2)
using namespace std;
const int maxn=200005;
int n,m,rev[maxn],ls[maxn],rs[maxn],fa[maxn],jingdu[maxn],siz[maxn];
bool isroot(int x) { return ls[fa[x]]!=x&&rs[fa[x]]!=x; }
void putup(int x)
{
	siz[x]=siz[ls[x]]+siz[rs[x]]+1;
}
void zigzag(int x,int knd)
{
	int y=fa[x],z=fa[y];
	if(!isroot(y))
	{
		if(ls[z]==y) ls[z]=x;
		else rs[z]=x;
	}
	fa[x]=z; fa[y]=x;
	if(knd==1)
	{
		ls[y]=rs[x];
		fa[ls[y]]=y;
		rs[x]=y;
	}
	else
	{
		rs[y]=ls[x];
		fa[rs[y]]=y;
		ls[x]=y;
	}
	putup(y); putup(x);
}
void putdowm(int x)
{
	if(!rev[x]) return;
	swap(ls[x],rs[x]); rev[ls[x]]^=1; rev[rs[x]]^=1; 
	rev[x]=0;
}
int sta[maxn];
void splay(int x)
{
	int top=0; sta[++top]=x;
	for(int i=x;!isroot(i);i=fa[i]) { sta[++top]=fa[i]; }
	while(top) putdowm(sta[top--]);
	while(!isroot(x))
	{
		int y=fa[x],z=fa[y];
		if(isroot(y))
		{
			if(ls[y]==x) zig(x);
			else zag(x);
		}
		else
		{
			if(ls[z]==y)
			{
				if(ls[y]==x) { zig(y); zig(x); }
				else { zag(x); zig(x); }
			}
			else
			{
				if(rs[y]==x) { zag(y); zag(x); }
				else { zig(x); zag(x); }
			}
		}
	}
}
void acc(int x)
{
	for(int y=0;x;y=x,x=fa[x])
	{
		splay(x);
		rs[x]=y;
		putup(x);
	}
}
void setroot(int x)
{
	acc(x); splay(x); rev[x]^=1;
}
void link(int a,int b)
{
	setroot(a); fa[a]=b;
}
void cut(int a,int b)
{
	setroot(a); acc(b); splay(b);
	ls[b]=fa[a]=0;
}
int getroot(int a)
{
	acc(a); splay(a);
	while(ls[a]) a=ls[a];
	return a;
}
int ans(int x)
{
	setroot(x); acc(n+1); splay(n+1); return siz[n+1]-1;
}
void change(int x,int y)
{
	cut(x,min(jingdu[x]+x,n+1)); jingdu[x]=y; link(x,min(x+jingdu[x],n+1));
}

int main()
{
	int x,y,z;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&jingdu[i]);
		link(i,min(jingdu[i]+i,n+1));
	}
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d",&x);
		if(x==1)
		{
			scanf("%d",&y); ++y;
			printf("%d\n",ans(y));
		}
		else
		{
			scanf("%d%d",&y,&z); ++y;
			change(y,z);
		}
	}
}

 

 

posted @ 2018-04-05 00:36  Newuser233  阅读(7)  评论(0)    收藏  举报