[BZOJ2002] [HNOI2010] 弹飞绵羊 - Link-Cut-Tree (LCT)

        LCT绝对的模板题啊(黄学长一开始用分块写的感觉很高端啊%%%

        呐……LCT写起来也是很简单的啊……根本不用维护一些其他的东西,只要最基本的操作。询问都不用别的直接makeroot然后access然后splay就好……

        好吧具体看代码。建议在最后加一个点n+1(感觉不加我就不会写

#include "algorithm"
#include "iostream"
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include "vector"
#include "math.h"
#include "map"
#include "set"

#define rep(f,a,b) for(f=a;f<=b;f++)

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*10+ch-'0';ch=getchar();}
	return x*f;
}

struct node {
	node *fa,*c[2];
	int size;
	bool rev;
	node ();
	void push_up();
	void push_down();
} Tnull,*null=&Tnull;

const int N=200005;
int n,a[N],q; node v[N];

node :: node(){
	fa=c[0]=c[1]=null;
	size=0; rev=false;
}

void node :: push_up(){
	size=c[0]->size+c[1]->size+1;
}

void node :: push_down(){
	if (fa->c[0]==this || fa->c[1]==this)
		fa->push_down();
	if(rev){
		c[0]->rev^=1;
		c[1]->rev^=1;
		swap(c[0],c[1]);
		rev=false;
	}
}

inline bool isroot (node *x){
	return x->fa->c[0]!=x && x->fa->c[1]!=x;
}

void rotate (node *x){
	node *y=x->fa,*z=y->fa;
	if (z!=null){
	   	if(z->c[0]==y) z->c[0]=x;
	   	if(z->c[1]==y) z->c[1]=x;
	}
	int l=y->c[1]==x,r=l^1;
	if(x->c[r]!=null) x->c[r]->fa=y;
	x->fa=z; y->fa=x; y->c[l]=x->c[r];
	x->c[r]=y; y->push_up(); x->push_up();
}

void splay (node *x){
	x->push_down();
	while (isroot(x)^1){
		node *y=x->fa,*z=y->fa;
		if(isroot(y)^1){
			if (z->c[0]==y ^ y->c[0]==x) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	x->push_up();
}

void access (node *x){
	for (node *y=null;x!=null;y=x,x=x->fa)
		splay(x),x->c[1]=y,x->push_up();
}

void makeroot (node *x){
	access(x); splay(x);
	x->rev^=1;
}

void link (node *x,node *y){
	makeroot(x);
	x->fa=y;
}

void cut (node *x,node *y){
	makeroot(x); access(y);
	splay(y); x->fa=null;
	y->c[0]=null; y->push_up();
}

int work (node *x){
	makeroot(v+n+1);
	access(x); splay(x);
	x->push_down();
	return x->size-1;
}

int main(){
	int i; n=read();
	rep(i,1,n){ a[i]=read();
		if(i+a[i]<=n)
		link(v+i,v+i+a[i]);
		else link(v+i,v+n+1);
	} v[n+1].size=1;
	int type,tot,pos; q=read();
	rep(i,1,q){ type=read();
		if(type==1){ pos=read(); pos++;
		 printf("%d\n",work(v+pos));}
		else { pos=read(); tot=read(); pos++;
		 if(pos+a[pos]<=n)cut(v+pos,v+pos+a[pos]); else cut(v+pos,v+n+1);
		 if(pos+tot<=n)link(v+pos,v+pos+(a[pos]=tot));
		 else link(v+pos,v+n+1),a[pos]=tot;
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值