蒟蒻TJY的博客

[Link-Cut-Tree][BZOJ2002]弹飞绵羊

题面

Description

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

Input

第一行包含一个整数\(n\),表示地上有\(n\)个装置,装置的编号从\(0\)\(n-1\)
接下来一行有\(n\)个正整数,依次为那\(n\)个装置的初始弹力系数。
第三行有一个正整数\(m\)
接下来\(m\)行每行至少有两个数\(i,j\),若\(i=1\),你要输出从\(j\)出发被弹几次后被弹飞,若\(i=2\)则还会再输入一个正整数\(k\),表示第\(j\)个弹力装置的系数被修改成\(k\)

Output

对于每个\(i=1\)的情况,你都要输出一个需要的步数,占一行。

Sample Input

4
1 2 1 1
3
1 1
2 1 1
1 1

Sample Output

2
3

Hint

对于20%的数据\(n,m\le 10000\);
对于100%的数据\(n\le 200000,m\le 100000\);


1.如何建树?

  • 若从这个点\(x\)会被弹飞,连边\((x,n+1)\)
  • 若从这个点\(x\)不会被弹飞,连边\((x,x+k_x)\)

根为\(\textbf{n+1}\)

以样例做例子:

2.如何询问?

哈?
由于splay是按深度关键字排序,所以根的左子树的大小就是要被弹几次了呀。

3.如何修改?

把原来的边删了在连新的不就完了吗……


代码

#include<iostream>
#include<cstdio>
using namespace std;
int ch[200002][2],fa[200002],siz[200002],num[200002],lazr[200002],cnt,n,q;
inline unsigned rd(){
	unsigned re=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){
		re=re*10+ch-'0';
		ch=getchar();
	}
	return re;
}
inline bool isroot(int bt){return ch[fa[bt]][0]!=bt&&ch[fa[bt]][1]!=bt;}
inline int drct(int bt){return ch[fa[bt]][1]==bt;}
inline void pushup(int bt){siz[bt]=siz[ch[bt][0]]+siz[ch[bt][1]]+1;}
inline void reverse(int bt){swap(ch[bt][0],ch[bt][1]);lazr[bt]^=1;}
inline void pd(int bt){
	if(lazr[bt]){
		if(ch[bt][0])reverse(ch[bt][0]);
		if(ch[bt][1])reverse(ch[bt][1]);
		lazr[bt]=0;
	}
}
inline void pushdown(int u){
	if(!isroot(u))pushdown(fa[u]);
	pd(u);
}
inline void rotate(int u){
	int f=fa[u],g=fa[f],c=drct(u);
	if(!isroot(f))ch[g][drct(f)]=u;
	fa[u]=g;
	ch[f][c]=ch[u][c^1];
	if(ch[f][c])fa[ch[f][c]]=f;
	ch[u][c^1]=f;
	fa[f]=u;
	pushup(f);
	pushup(u);
}
void splay(int u){
	pushdown(u);
	while(!isroot(u)){
		if(!isroot(fa[u]))rotate(drct(fa[u])==drct(u)?fa[u]:u);
		rotate(u);
	}
}
void access(int u){
	for(int v=0;u;v=u,u=fa[u]){
		splay(u);
		ch[u][1]=v;
		pushup(u);
	}
}
void makeroot(int u){
	access(u);
	splay(u);
	reverse(u);
}
void link(int a,int b){
	makeroot(a);
	fa[a]=b;
}
void cut(int a,int b){
	makeroot(a);
	access(b);
	splay(b);
	ch[b][0]=0;
	fa[a]=0;
	pushup(b);
}
int main(){
	n=rd();
	for(int i=1;i<=n;i++){
		num[i]=rd();
		siz[i]=1;
	}
	for(int i=1;i<=n;i++){
		if(i+num[i]<=n)fa[i]=i+num[i];
		else fa[i]=n+1;
	}
	q=rd();
	for(int i=1;i<=q;i++){
		int opt=rd(),x=rd()+1;
		if(opt==1){
			makeroot(n+1);
			access(x);
			splay(x);
			printf("%d\n",siz[ch[x][0]]);
		}else{
			int y=rd();
			if(x+num[x]<=n)cut(x,x+num[x]);
			else cut(x,n+1);
			num[x]=y;
			if(x+num[x]<=n)link(x,x+num[x]);
			else link(x,n+1);
		}
	}
}
posted @ 2018-07-28 18:24  蒟蒻TJY  阅读(198)  评论(0编辑  收藏  举报