[HNOI2010]弹飞绵羊

传送门

Description

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

Solution

水题已经越来越少了呢

首先发现所有路径组成一个树的结构,每次修改相当于移动一整棵子树

直接\(LCT\)维护即可

发现距离就是链的\(siz-1\),直接\(access\)一下就行


Code 

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)>(b)?(b):(a))
#define reg register
using namespace std;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
const int MN=2e5+5; 
class Link_Cut_Tree
{        
	int c[MN][2],fa[MN],siz[MN];
	bool get(int x){return c[fa[x]][1]==x;}
	bool nrt(int x){return c[fa[x]][0]==x||c[fa[x]][1]==x;}
	void up(int x){siz[x]=siz[c[x][1]]+siz[c[x][0]]+1;}
	int rtt(int x)
	{
		int y=fa[x],z=fa[y],l=get(x),r=l^1;if(nrt(y))c[z][get(y)]=x;fa[x]=z;
		fa[c[x][r]]=y;c[y][l]=c[x][r];c[x][r]=y;fa[y]=x;up(y);
	}
	void Splay(int x)
	{
		for(;nrt(x);rtt(x))
			if(nrt(fa[x])) rtt(get(x)^get(fa[x])?x:fa[x]);
		up(x);
	}
	void acs(int x){for(reg int i=0;x;x=fa[i=x])Splay(x),c[x][1]=i,up(x);}
	public:
		void init(int N){for(reg int i=1;i<=N+1;++i)siz[i]=1;}
		void link(int x,int y){fa[x]=y;}
		void cut(int x){acs(x);Splay(x);fa[c[x][0]]=0;c[x][0]=0;up(x);}
		int que(int x){acs(x);Splay(x);return siz[x]-1;}
}T;
int k[MN];
int main()
{
	reg int i,N,M;N=read();T.init(N);
	for(i=1;i<=N;++i) k[i]=read(),T.link(i,min(i+k[i],N+1));
	M=read();
	while(M--)
	{
		i=read();
		if(i==1) printf("%d\n",T.que(read()+1));
		else i=read()+1,T.cut(i),k[i]=read(),T.link(i,min(i+k[i],N+1));
	}
	return 0;
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

posted @ 2019-04-05 21:58  PaperCloud  阅读(137)  评论(0编辑  收藏  举报