P3203 [HNOI2010]弹飞绵羊

题目描述

某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

输入输出格式

输入格式:

第一行包含一个整数n,表示地上有n个装置,装置的编号从0到n-1。

接下来一行有n个正整数,依次为那n个装置的初始弹力系数。

第三行有一个正整数m,

接下来m行每行至少有两个数i、j,若i=1,你要输出从j出发被弹几次后被弹飞,若i=2则还会再输入一个正整数k,表示第j个弹力装置的系数被修改成k。

输出格式:

对于每个i=1的情况,你都要输出一个需要的步数,占一行。

输入输出样例

输入样例#1:  复制
4
1 2 1 1
3
1 1
2 1 1
1 1
输出样例#1:  复制
2
3

说明

对于20%的数据n,m<=10000,对于100%的数据n<=200000,m<=100000

用这题来练练LCT吧……话说wjz大佬讲的LCT几乎没怎么听懂啊QAQ我好菜

话说关于LCT,这两位大佬的blog很不错

http://www.cnblogs.com/zwfymqz/p/8972914.html#_label5

http://www.cnblogs.com/flashhu/p/8324551.html

首先我们考虑,对于每一个节点,向他被弹到的节点连边。即对于所有节点建一棵树,i节点的父亲为从i装置会被弹飞到哪一个装置。

我们定义一个虚拟节点n+1,让所有被弹飞到大于n的点连到n+1。可以看出,到了n+1就意味着已经被弹飞

对于修改操作,先将点与原先的连边cut,再link到新的点上

对于查询操作,我们依次执行makeroot(x),access(y),splay(y),这个时候可以发现x的深度即为答案。而因为此时splay已经是一条链,所以答案就是sz[y]-1(sz表示以y为根的子树的大小)

 1 //minamoto
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cctype>
 5 #define N 200005
 6 using namespace std;
 7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<15,stdin),p1==p2)?EOF:*p1++)
 8 char buf[1<<15],*p1=buf,*p2=buf;
 9 inline int read(){
10     #define num ch-'0'
11     char ch;bool flag=0;int res;
12     while(!isdigit(ch=getc()))
13     (ch=='-')&&(flag=true);
14     for(res=num;isdigit(ch=getc());res=res*10+num);
15     (flag)&&(res=-res);
16     #undef num
17     return res;
18 }
19 namespace lct{
20     int top,s[N],ch[N][2],fa[N],sz[N],v[N];bool rev[N];
21     inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
22     inline void pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
23     inline void pushdown(int x){if(rev[x])swap(ch[x][0],ch[x][1]),rev[ch[x][0]]^=1,rev[ch[x][1]]^=1,rev[x]^=1;}
24     inline void rotate(int x){
25         int y=fa[x],z=fa[y],d=(ch[y][1]==x);if(!isroot(y)) ch[z][ch[z][1]==y]=x;
26         fa[x]=z,fa[y]=x;fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y;pushup(y),pushup(x);
27     }
28     inline void splay(int x){
29         s[top=1]=x;for(int i=x;!isroot(i);i=fa[i]) s[++top]=fa[i];for(int i=top;i>=1;--i) pushdown(s[i]);
30         for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){
31             if(!isroot(y)) ((ch[z][1]==y)^(ch[y][1]==x))?rotate(x):rotate(y);rotate(x);
32         }
33     }
34     inline void access(int x){int t=0;while(x){splay(x),ch[x][1]=t,pushup(x),t=x,x=fa[x];}}
35     inline void makeroot(int x){access(x),splay(x),rev[x]^=1;}
36     inline void split(int x,int y){makeroot(x),access(y),splay(y);}
37     inline void link(int x,int y){makeroot(x);fa[x]=y;}
38     inline void cut(int x,int y){makeroot(x);access(y),splay(y);fa[x]=ch[y][0]=0;pushup(y);}
39     inline int query(int x,int y){makeroot(x),access(y),splay(y);return sz[y]-1;}
40 }
41 using namespace lct;
42 int main(){
43     //freopen("testdata.in","r",stdin);
44     int n,m;
45     n=read();
46     for(int i=1;i<=n+1;++i) sz[i]=1;
47     for(int i=1;i<=n;++i){
48         v[i]=read();
49         if(i+v[i]<=n) link(i,i+v[i]);
50         else link(i,n+1);
51     }
52     m=read();
53     while(m--){
54         int opt=read(),i=read();++i;
55         if(opt==1){
56             printf("%d\n",query(i,n+1));
57         }
58         else{
59             int k=read();
60             cut(i,i+v[i]<=n?i+v[i]:n+1);
61             link(i,i+k<=n?i+k:n+1);
62             v[i]=k;
63         }
64     }
65     return 0;
66 }

猜你喜欢

转载自www.cnblogs.com/bztMinamoto/p/9325828.html