【bzoj 4764】弹飞大爷

Description

自从WC退役以来,大爷是越来越懒惰了。为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们决定齐心合力构造一个下面这样的序列。这个序列共有N项,每项都代表了一个小伙伴的力量值,如果大爷落到了第i个小伙伴的手里,那么第i个小伙伴会把大爷弹到第i+ai个小伙伴手里,其中ai就是第i个小伙伴的力量值,也就是序列的第i项。然而,因为大爷太沉了,所以有些小伙伴不能撑到锻(you)炼(xi)结束,所以我们中途会替换一些小伙伴,也就是改变序列的某些项。而且,因为大爷太沉了,所以有些小伙伴不能把大爷扔向前方,而是会把大爷往反方向扔,也就是序列中的一些项会是负的(当然,也可能是零喽)。现在机智的大爷通过在空中的观察,已经知道小伙伴们的所有活动——即初始序列、所有更改操作,他想请你算一算,如果他在某时刻落到了某个位置,那么他会在几次弹起之后落到小伙伴序列之外(毕竟摔在地上还是蛮疼的)。

Input

第一行为两个整数N和M,代表序列长度和操作次数。

第二行为N个整数,代表初始的小伙伴序列。

接下来有M行,每行代表一个操作。

如果这一行的第一个数是1,代表该操作是一个询问操作,接下来一个数X,代表询问此时大爷从X处,经过几次弹起会摔在地上。如果永远不会摔在地上,请输出-1。

如果这一行的第一个数是2,代表该操作是一个更改操作,接下来两个数X,Y,代表将序列的第X项改为Y。

N,M <= 200000  |Ai| < N

Output

对于每次询问操作,输出弹起次数或-1。

Sample Input

3 19

1 1 1

1 1

1 2

1 3

2 1 2

1 1

1 2

1 3

2 3 -1

1 1

1 2

1 3

2 2 233

1 1

1 2

1 3

2 2 -233

1 1

1 2

1 3

Sample Output

3

2

1

2

2

1

-1

-1

-1

3

1

2

3

1

2

调了两天终于A了……万分感谢czl大爷、cyc大爷和yy大爷。

RE了几发之后一直调不出来,心态爆炸开始乱搞,然后就WA了。怪我自己没有理解好写法。

因为有环,所以需要隐藏环上的一条边来使其成为森林,hl数组与hr数组即代表隐藏边的端点。

剩下的直接上代码……

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 const int N=200050;
  6 int n,m,t,u,v,a[N],hl[N],hr[N],st[N];
  7 struct node{int fa,c[2],s;bool rev;}tr[5*N];
  8 int read()
  9 {
 10     int x=0,f=1;char c=getchar();
 11     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
 12     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
 13     return x*f;
 14 }
 15 bool isroot(int k){return !k||!tr[k].fa||(tr[tr[k].fa].c[0]!=k&&tr[tr[k].fa].c[1]!=k);}
 16 void up(int k){tr[k].s=tr[tr[k].c[0]].s+tr[tr[k].c[1]].s+1;}
 17 void down(int k)
 18 {
 19     int l=tr[k].c[0],r=tr[k].c[1];
 20     if(tr[k].rev)
 21     {
 22         tr[k].rev^=1;tr[l].rev^=1;tr[r].rev^=1;
 23         swap(tr[k].c[0],tr[k].c[1]);
 24     }
 25     if(l)hl[l]=hl[k],hr[l]=hr[k];
 26     if(r)hl[r]=hl[k],hr[r]=hr[k];
 27 }
 28 void rotate(int x)
 29 {
 30     int y=tr[x].fa,z=tr[y].fa,l,r;
 31     if(tr[y].c[0]==x)l=0;else l=1;r=l^1;
 32     if(!isroot(y)){if(tr[z].c[0]==y)tr[z].c[0]=x;else tr[z].c[1]=x;}
 33     tr[x].fa=z;tr[y].fa=x;tr[tr[x].c[r]].fa=y;
 34     tr[y].c[l]=tr[x].c[r];tr[x].c[r]=y;
 35     up(y);up(x);
 36 }
 37 void splay(int x)
 38 {
 39     int top=0;st[++top]=x;
 40     for(int i=x;!isroot(i);i=tr[i].fa)st[++top]=tr[i].fa;
 41     for(int i=top;i;i--)down(st[i]);
 42     while(!isroot(x))
 43     {
 44         int y=tr[x].fa,z=tr[y].fa;
 45         if(!isroot(y))
 46         {
 47             if((tr[y].c[0]==x)^(tr[z].c[0]==y))rotate(x);
 48             else rotate(y);
 49         }
 50         rotate(x);
 51     }
 52 }
 53 void acs(int x)
 54 {
 55     int t=0;
 56     while(x){splay(x);tr[x].c[1]=t;up(x);t=x;x=tr[x].fa;}
 57 }
 58 void mkroot(int x){acs(x);splay(x);tr[x].rev^=1;}
 59 int find(int x){acs(x);splay(x);while(tr[x].c[0])x=tr[x].c[0];return x;}
 60 void link(int x,int y){mkroot(x);tr[x].fa=y;acs(x);splay(x);}
 61 void cut(int x,int y)
 62 {
 63     mkroot(x);acs(y);splay(y);
 64     tr[x].fa=tr[y].c[0]=0;up(y);
 65     hl[x]=hr[x]=hl[y]=hr[y]=0;
 66 }
 67 void xlink(int x,int y)
 68 {
 69     if(find(x)==find(y))hl[y]=x,hr[y]=y;
 70     else link(x,y);
 71 }
 72 void xcut(int x,int y)
 73 {
 74     acs(x);splay(x);int li=hl[x],ri=hr[x];
 75     if(hl[x]==x&&hr[x]==y)hl[x]=hl[y]=hr[x]=hr[y]=0;
 76     else
 77     {
 78         cut(x,y);
 79         if(li&&ri)xlink(li,ri);//划重点!xlink而不是link。
 80     }
 81 }
 82 int query(int x)
 83 {
 84     mkroot(n+1);acs(x);splay(x);
 85     if(hl[x]&&hr[x])return -1;
 86     return tr[x].s-1;
 87 }
 88 int main()
 89 {
 90     n=read();m=read();
 91     for(int i=1;i<=n+1;i++)tr[i].s=1;
 92     for(int i=1;i<=n;i++)
 93     {
 94         a[i]=read();
 95         if(i+a[i]<=0||i+a[i]>n)link(i,n+1);
 96         else xlink(i,i+a[i]);
 97     }
 98     while(m--)
 99     {
100         t=read();
101         if(t==1)u=read(),printf("%d\n",query(u));
102         else
103         {
104             u=read();v=read();
105             if(u+a[u]<=0||u+a[u]>n)cut(u,n+1);
106             else xcut(u,u+a[u]);
107             if(u+v<=0||u+v>n)link(u,n+1);
108             else xlink(u,u+v);
109             a[u]=v;
110         }
111     }
112     return 0;
113 }

时间: 2024-08-05 02:54:05

【bzoj 4764】弹飞大爷的相关文章

BZOJ 4764: 弹飞大爷

4764: 弹飞大爷 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 4  Solved: 4[Submit][Status][Discuss] Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们 决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值,如果大爷落到了 第i个小伙伴的手里,那么第i个小伙伴会把大爷弹到第i+ai个小伙伴手里,其中

【BZOJ】4764 弹飞大爷

[算法]Link-Cut Tree [题意]一个n个数字组成的序列,a[i]表示移动到i+a[i]处,序列值可动态修改,求从i处开始移动到序列外的最小步数. [题解]将序列视为n个点,外界视为n+1,则每个点有且只有一条边连出去,由该性质可知是一个基环内向森林,问题转化为支持插入删除边并求点(n+1)到点i的距离. 由基环内向森林以及点n+1不能向外出边可知点n+1必然在无环的树上,所以若出现环则输出-1.

【LCT维护基环内向树森林】BZOJ4764 弹飞大爷

4764: 弹飞大爷 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 101  Solved: 52[Submit][Status][Discuss] Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们 决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值,如果大爷落到了 第i个小伙伴的手里,那么第i个小伙伴会把大爷弹到第i+ai个小伙伴手里

【BZOJ4764】弹飞大爷 LCT

[BZOJ4764]弹飞大爷 Description 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值,如果大爷落到了第i个小伙伴的手里,那么第i个小伙伴会把大爷弹到第i+ai个小伙伴手里,其中ai就是第i个小伙伴的力量值,也就是序列的第i项.然而,因为大爷太沉了,所以有些小伙伴不能撑到锻(you)炼(xi)结束,所以我们中途会替换一些小伙伴,也就是改变序列的

[BZOJ 2002] 弹飞绵羊 LCT

题意 给定 n 个装置, 每个装置有系数 K[i] . 在点 i 的绵羊会被弹到 i + K[i] , 如果 i + K[i] > n , 则定义为被弹飞. m 次操作, 每次操作是下面的某种: ① 更改某个装置的系数 K[x] = y . ② 问一只从装置 x 出发的绵羊几次被弹飞. n <= 200000 . 实现 1. 不需要换根. 2. par[x] 指当前子树中深度最小的点的父亲. c[x][0] 的子树指深度比当前点小的一些祖先. c[x][1] 的子树指深度比当前点大的一条后继.

bzoj4764 弹飞大爷 LCT

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4764 题解 如果 \(a_i > 0\) 的话,那么就是 bzoj2002 的原题.直接用 LCT 维护就可以了. 但是现在这个题因为 \(a_i\) 任意,所以不能保证每个点向弹向的点连边一定是一棵树. 但是因为每个点的出边只有一条,所以一定是基环树森林. 考虑如何用 LCT 维护基环树. 首先这个环一定出现在根的位置.所以不妨用一个变量存一下这个根有没有额外的环边. link 的时候,如

bzoj4764 弹飞大爷

我是萌萌的传送门 你们搞的这个题目啊,exciting!-- LCT裸题嘛.记得特判一下根节点所连出的边是否会成环就行了,还有删边的时候特判一下是否需要把这条边加回去. 几天不写LCT,结果一写就写出各种脑残错误,我怎么这么菜,233-- 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define isroot(x) ((x)->p==null||((x)->p->ch[

bzoj4764: 弹飞大爷 link-cut-tree

题目传送门 这道题啊 调了一个晚上 因为写的是一个有根树和n个基环的写法 所以写得很奇怪..... 最后发现单独处理树的时候不能随意改变S(就是原来的根)不然size会出错.... #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int M=250007; int read(){ int ans=0,f=1

【bzoj 2002】弹飞绵羊

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