P3203 [HNOI2010]弹飞绵羊

题目

P3203 [HNOI2010]弹飞绵羊

做法

本来以为是个水题,其实还是有思维性的

\(LCT\)上操作和模板一样,显然我们维护子树大小

开始是想\(Link(x,x+val[x])\)\(x+val[x]>n\)时就不连,然后查询\(x\)时就查询右子树大小

反例就不举了随手就是个反例吧反正这种办法是错的

正解:\(Link(x,x+val[x])\)\(x+val[x]>n\)\(Link(x,n+1)\)

查询\(x\)时其实就是查询\(x\)~\(n+1\)这条链:\(Makeroot(x); Access(n+1); Splay(n+1);\),输出\(size[n+1]-1\)

My complete code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<cmath>
#include<stack>
using namespace std;
typedef int LL;
const LL maxn=1e6;
inline LL Read(){
	LL x(0),f(1);char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
LL n,m;
LL size[maxn],fa[maxn],son[maxn][2],r[maxn],val[maxn];

inline bool Notroot(LL x){
	return (son[fa[x]][0]==x||son[fa[x]][1]==x);
}
inline void Pushr(LL x){
	swap(son[x][0],son[x][1]);r[x]^=1;
}
inline void Pushdown(LL x){
	if(r[x]){
		if(son[x][0])Pushr(son[x][0]);
		if(son[x][1])Pushr(son[x][1]);
		r[x]^=1;
	}
}
inline void Update(LL x){
	size[x]=1+size[son[x][0]]+size[son[x][1]];
}
inline void Rotate(LL x){
	LL y(fa[x]),z(fa[y]),lz=(son[y][1]==x);
	if(Notroot(y))
		son[z][son[z][1]==y]=x;
	fa[x]=z;
	son[y][lz]=son[x][lz^1];
	if(son[y][lz])
	    fa[son[y][lz]]=y;
	son[x][lz^1]=y;fa[y]=x;
	Update(y),Update(x);
}
LL sta[maxn];
inline void Splay(LL x){
	LL y(x),top(0);
	sta[++top]=y;
	while(Notroot(y)) sta[++top]=y=fa[y];
	while(top) Pushdown(sta[top--]);
	while(Notroot(x)){
		y=fa[x];
		if(Notroot(y)){
			LL z=fa[y];
			if(((son[z][1]==y)^(son[y][1]==x))==0) Rotate(y);
			else Rotate(x);
		}
		Rotate(x);
	}
}
inline void Access(LL x){
	for(LL y=0;x;y=x,x=fa[x]){
		Splay(x),son[x][1]=y;Update(x);
	}
}
inline void Makeroot(LL x){
	Access(x),Splay(x),Pushr(x);
}
inline void Split(LL x,LL y){
	Makeroot(x),Access(y),Splay(y);
}

inline void Link(LL x,LL y){
	Makeroot(y);
	fa[y]=x;
}
inline void Delet(LL x,LL y){
	Split(x,y);
	fa[x]=son[y][0]=0;
	Update(y);
}
int main(){
	n=Read();
	for(LL i=1;i<=n;++i) size[i]=1;
	for(LL i=1;i<=n;++i){
		val[i]=Read();
		if(i+val[i]<=n)
		    Link(i,i+val[i]);
		else
		    Link(i,n+1);
	}
	m=Read();
	while(m--){
		LL op(Read());
		if(op==1){
			LL x(Read()+1);
			Makeroot(x); Access(n+1); Splay(n+1);
			printf("%d\n",size[n+1]-1);
		}else{
			LL x(Read()+1),y(Read());
			if(x+val[x]<=n) Delet(x,x+val[x]);
			else Delet(x,n+1);
			val[x]=y;
			if(x+val[x]<=n) Link(x,x+val[x]);
			else Link(x,n+1);
		}
	}
}
posted @ 2019-01-26 13:43  y2823774827y  阅读(161)  评论(0编辑  收藏  举报