BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊 LCT
2002: [Hnoi2010]Bounce 弹飞绵羊
Time Limit: 1 Sec
Memory Limit: 256 MB
题目连接
http://www.lydsy.com/JudgeOnline/problem.php?id=2002Description
某天,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的情况,你都要输出一个需要的步数,占一行。
Sample Input
4
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
2
3
HINT
题意
有link操作,cut操作,查询子树大小
题解:
动态树裸题……
其实就是查询子树大小啦
连边过去就吼了
代码:
//qscqesze #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <cmath> #include <cstring> #include <ctime> #include <iostream> #include <algorithm> #include <set> #include <bitset> #include <vector> #include <sstream> #include <queue> #include <typeinfo> #include <fstream> #include <map> #include <stack> typedef long long ll; using namespace std; //freopen("D.in","r",stdin); //freopen("D.out","w",stdout); #define sspeed ios_base::sync_with_stdio(0);cin.tie(0) #define maxn 200500 #define mod 1000000007 #define eps 1e-9 #define e exp(1.0) #define PI acos(-1) #define lowbit(x) (x)&(-x) const double EP = 1E-10 ; int Num; //const int inf=0x7fffffff; const ll inf=999999999; inline ll read() { ll 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; } //************************************************************************************* const int MAXN = 200500; struct Node { Node *ch[2], *p; int size, value; bool rev; Node(int t = 0); inline bool dir(void) {return p->ch[1] == this;} inline void SetC(Node *x, bool d) { ch[d] = x; x->p = this; } inline void Rev(void) { swap(ch[0], ch[1]); rev ^= 1; } inline void Push(void) { if (rev) { ch[0]->Rev(); ch[1]->Rev(); rev = 0; } } inline void Update(void) { size = ch[0]->size + ch[1]->size + 1; } }Tnull, *null = &Tnull, *fim[MAXN]; // 要记得额外更新null的信息 Node::Node(int _value){ch[0] = ch[1] = p = null; rev = 0;} inline bool isRoot(Node *x) {return x->p == null || (x != x->p->ch[0] && x != x->p->ch[1]);} inline void rotate(Node *x) { Node *p = x->p; bool d = x->dir(); p->Push(); x->Push(); if (!isRoot(p)) p->p->SetC(x, p->dir()); else x->p = p->p; p->SetC(x->ch[!d], d); x->SetC(p, !d); p->Update(); } inline void splay(Node *x) { x->Push(); while (!isRoot(x)) { if (isRoot(x->p)) rotate(x); else { if (x->dir() == x->p->dir()) {rotate(x->p); rotate(x);} else {rotate(x); rotate(x);} } } x->Update(); } inline Node* Access(Node *x) { Node *t = x, *q = null; for (; x != null; x = x->p) { splay(x); x->ch[1] = q; q = x; } splay(t); //info will be updated in the splay; return q; } inline void Evert(Node *x) { Access(x); x->Rev(); } inline void link(Node *x, Node *y) { Evert(x); x->p = y; } inline Node* getRoot(Node *x) { Node *tmp = x; Access(x); while (tmp->Push(), tmp->ch[0] != null) tmp = tmp->ch[0]; splay(tmp); return tmp; } // 一定要确定x和y之间有边 inline void cut(Node *x, Node *y) { Access(x); splay(y); if (y->p != x) swap(x, y); Access(x); splay(y); y->p = null; } inline Node* getPath(Node *x, Node *y) { Evert(x); Access(y); return y; } inline void clear(void) { null->rev = 0; null->size = 0; null->value = 0; } int a[maxn]; int main() { clear(); int n=read(); for(int i=0;i<=n+1;i++) fim[i] = new Node(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) { int p = i+a[i]; if(p>n)p=n+1; link(fim[i],fim[p]); } int m = read(); while(m--) { int op = read(); if(op == 1) { int x = read(); x++; Access(fim[x]); splay(fim[x]); printf("%d\n",fim[x]->size - 1); } else { int x=read(),y=read(); x++; int p = x+a[x]; if(p>n)p=n+1; cut(fim[x],fim[p]); a[x]=y; p = x+a[x]; if(p>n)p=n+1; link(fim[x],fim[p]); } } }