bzoj 2002: 弹飞绵羊 Link-Cut-Tree

题目:

Description
某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。
Input
第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1,接下来一行有n个正整数,依次为那n个装置的初始弹力系数。第三行有一个正整数m,接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输
入一个正整数k,表示第j个弹力装置的系数被修改成k。对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000
Output
对于每个i=1的情况,你都要输出一个需要的步数,占一行。

题解:

我们将每个坐标视作一个点
对于每一个\(a_i我们将其视为连接\)(i+a_i,i)\(的一条树边. 表示可以从点i到达点\)(i+a_i)\(对于所有的\)(i+a_i) > n$我们令其为n+1
然后对于每一次询问x,即查询以x为根的时候点(n+1)的深度。
又要求支持修改,所以我们大力上LCT即可.

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
typedef long long ll;
inline void read(int &x){
	x=0;char ch;bool flag = false;
	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 200010;
int n;
namespace Splay{
	struct Node{
		Node *ch[2],*fa;
		int siz;
		void update(){
			siz = ch[0]->siz + ch[1]->siz + 1;
		}
	}*null;
	Node mem[maxn],*it;
	inline void init(){
		it = mem;null = it++;null->ch[0] = null->ch[1] = null;
		null->fa = null;null->siz = 0;
	}
	inline Node* newNode(){
		Node *p = it++;p->ch[0] = p->ch[1] = p->fa = null;
		p->siz = 1;return p;
	}
	inline void rotate(Node *p,Node *x){
		int k = p == x->ch[1];
		Node *y = p->ch[k^1],*z = x->fa;
		if(z->ch[0] == x) z->ch[0] = p;
		if(z->ch[1] == x) z->ch[1] = p;
		if(y != null) y->fa = x;
		p->fa = z;p->ch[k^1] = x;
		x->fa = p;x->ch[k] = y;
		x->update();p->update();
	}
	inline bool isroot(Node *p){
		return p == null || (p->fa->ch[0] != p && p->fa->ch[1] != p);
	}
	inline void splay(Node *p){
		while(!isroot(p)){
			Node *x = p->fa,*y = x->fa;
			if(isroot(x)) rotate(p,x);
			else if(p == x->ch[0] ^ x == y->ch[0]) rotate(p,x),rotate(p,y);
			else rotate(x,y),rotate(p,x);
		}p->update();
	}
}
namespace LCT{
	inline void init(){
		Splay::init();
		for(int i=1;i<=n+1;++i) Splay::newNode();
	}
using namespace Splay;
	inline void Access(Node *u){
		Node *v = null;
		while(u != null){
			splay(u);u->ch[1] = v;
			v = u;u = u->fa;
		}
	}
	inline void link(Node *u,Node *v){
		Access(v);splay(v);
		v->fa = u;
	}
	inline void cut(Node *u,Node *v){
		Access(u);splay(u);
		Access(v);splay(v);
		splay(u);u->ch[1] = u->ch[1]->fa = null;
	}
	inline int query(Node *x){
		Access(x);splay(x);
		return x->ch[0]->siz;
	}
}
int a[maxn];
int main(){
	read(n);LCT::init();
	for(int i=1;i<=n;++i){
		read(a[i]);
		LCT::link(Splay::mem+min(i+a[i],n+1),Splay::mem+i);
	}
	int m;read(m);
	while(m--){
		int u,v;read(u);
		if(u == 1){
			read(u); ++ u;
			if(u > n) continue;
			printf("%d\n",LCT::query(Splay::mem + u));
		}else{
			read(u);read(v);++ u;
			LCT::cut(Splay::mem+min(u+a[u],n+1),Splay::mem+u);
			LCT::link(Splay::mem+min(u+v,n+1),Splay::mem+u);
			a[u] = v;
		}
	}
	getchar();getchar();
	return 0;
}
posted @ 2017-03-08 20:29  Sky_miner  阅读(175)  评论(0编辑  收藏  举报