bzoj2002 弹飞绵羊 LCT
2002: [Hnoi2010]Bounce 弹飞绵羊
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 6706 Solved: 3522
[Submit][Status][Discuss]
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的情况,你都要输出一个需要的步数,占一行。
Sample Input
4
1 2 1 1
3
1 1
2 1 1
1 1
1 2 1 1
3
1 1
2 1 1
1 1
Sample Output
2
3
3
显然这里不能换根,然后直接维护下size就可以了。
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000100; const int INF=1e9+10; int n,m; int op,x,k; int pre[maxn],ch[maxn][2]; int sz[maxn]; bool isroot(int x) { return ch[pre[x]][0]!=x&&ch[pre[x]][1]!=x; } void up(int x) { sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; } void rot(int x,int kind) { int y=pre[x]; ch[y][kind^1]=ch[x][kind]; pre[ch[x][kind]]=y; if(!isroot(y)) ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; up(y); } void splay(int x) { while(!isroot(x)){ if(isroot(pre[x])) rot(x,ch[pre[x]][0]==x); else{ int y=pre[x],z=pre[y]; int kind=ch[y][0]==x,one=0; if(ch[y][0]==x&&ch[z][0]==y) one=1; if(ch[y][1]==x&&ch[z][1]==y) one=1;; if(one) rot(y,kind),rot(x,kind); else rot(x,kind),rot(x,kind^1); } } up(x); } int access(int x) { int t=0; while(x){ splay(x); ch[x][1]=t; t=x;x=pre[x]; up(t); } return t; } int get(int x) { access(x); splay(x); return sz[ch[x][0]]; } void cut(int x) { access(x); splay(x); ch[x][0]=pre[ch[x][0]]=0; up(x); } void link(int x,int y) { access(x); splay(x); pre[x]=y; splay(x); } int main() { freopen("in.txt","r",stdin); while(cin>>n){ REP(i,0,n) pre[i]=0,MS0(ch[i]),sz[i]=i?1:0; REP(i,1,n){ scanf("%d",&k); if(i+k<=n) link(i,i+k); } cin>>m; REP(i,1,m){ scanf("%d%d",&op,&x);x++; if(op==1) printf("%d\n",get(x)+1); else{ scanf("%d",&k); cut(x); if(x+k<=n) link(x,x+k); } } } return 0; }
没有AC不了的题,只有不努力的ACMER!