[LCT]BZOJ 2002——[Hnoi2010]Bounce 弹飞绵羊

来源:互联网 发布:尤尼克斯淘宝真的 编辑:程序博客网 时间:2024/04/26 06:07

2002: [Hnoi2010]Bounce 弹飞绵羊

题目描述

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

解题思路

这是一道比较明显的动态树问题,初始时将ii+k[i]连起来,当要求修改x节点的弹力时,先将原来的边(i,i+k[i])断开,然后修正k[i]连接,因为要考虑弹飞的问题,所以我们设置n+1节点表示被弹飞,所以前面的i+k[i]都要和n+1min

#include<cstdio>#include<algorithm>using namespace std;const int maxn=200005;struct jz{    int s,son[2],f,flg;}a[maxn];int n,Q,k[maxn],top,stack[maxn];inline int _read(){    int num=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();    return num;}void pushup(int x){a[x].s=a[a[x].son[0]].s+a[a[x].son[1]].s+1;}void tag(int x){swap(a[x].son[0],a[x].son[1]);a[x].flg^=1;}void pushdown(int x){    if (!a[x].flg) return;    if (a[x].son[1]) tag(a[x].son[1]);    if (a[x].son[0]) tag(a[x].son[0]);    a[x].flg=0;}bool is_ro(int x){return x!=a[a[x].f].son[1]&&x!=a[a[x].f].son[0];}void rotate(int x){    int fa=a[x].f,d=x==a[fa].son[0];    if (!is_ro(fa)) a[a[fa].f].son[fa==a[a[fa].f].son[1]]=x;    a[fa].son[d^1]=a[x].son[d];a[a[x].son[d]].f=fa;a[x].son[d]=fa;    pushup(fa);pushup(x);a[x].f=a[fa].f;a[fa].f=x;}void splay(int x){    stack[++top]=x;    for (int i=x;!is_ro(i);i=a[i].f) stack[++top]=a[i].f;    while (top) pushdown(stack[top--]);    while (!is_ro(x)){        int fa=a[x].f;        if (!is_ro(fa)){            int d1=fa==a[a[fa].f].son[1],d2=x==a[fa].son[1];            if (d1==d2) rotate(fa);else rotate(x);        }        rotate(x);    }}void Access(int x){    int lst=0;    while(x){        splay(x);a[x].son[1]=lst;pushup(x);        lst=x;x=a[x].f;    }}void make_ro(int x){Access(x);splay(x);tag(x);}void link(int x,int y){make_ro(y);a[y].f=x;}void cut(int x,int y){    make_ro(y);Access(x);splay(x);    a[y].f=a[x].son[0]=0;pushup(x);}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    n=_read();    for (int i=1;i<=n+1;i++) a[i].s=1;    for (int i=1;i<=n;i++) k[i]=_read(),link(min(i+k[i],n+1),i);    Q=_read();    while (Q--){        int d=_read(),x=_read()+1,y;        if (d==1){            make_ro(n+1);Access(x);splay(x);            printf("%d\n",a[x].s-1);        }else cut(min(x+k[x],n+1),x),link(min(x+(k[x]=_read()),n+1),x);    }    return 0;}
原创粉丝点击