bzoj2002Bounce 弹飞绵羊

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

Sample Output
2
3

分析:
我们要把知道题转化为树形结构
每个弹射装置都只能弹向一个固定的位置
这是一对一的关系,就好像树上的爸爸和儿子
所以就把每个节点当作儿子,连到下一个位置(爸爸)

那要是弹飞了怎么办呢
我们把所有弹飞的绵羊都连到一个不存在的位置(比如说n+1)
整体思路还是很好想的
然而只有一个点我想不明白
就是,初始的时候正常连边,无论在查询时还是改变值时,x++
望神犇能帮忙解释一下

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=100001;
int pre[N],ch[N][2],q[N],size[N];
bool rev[N];
int n,a[N],m;

int get(int bh)
{

    return (ch[pre[bh]][0]==bh ? 0:1);  
}

int isroot(int bh)
{
    return ch[pre[bh]][0]!=bh&&ch[pre[bh]][1]!=bh;
}

void push(int bh)
{
    if (rev[bh])
    {
        rev[bh]^=1;
        rev[ch[bh][0]]^=1;
        rev[ch[bh][1]]^=1;
        swap(ch[bh][0],ch[bh][1]);
    }
}

void update(int bh)
{
    if (bh)
    {
        size[bh]=1;
        if (ch[bh][0]) size[bh]+=size[ch[bh][0]];
        if (ch[bh][1]) size[bh]+=size[ch[bh][1]];
    }
}

void rotate(int bh)
{
    int fa=pre[bh];
    int grand=pre[fa];
    int wh=get(bh);
    if (!isroot(fa)) ch[grand][ch[grand][0]==fa ? 0:1]=bh;
    ch[fa][wh]=ch[bh][wh^1];
    pre[ch[fa][wh]]=fa;
    ch[bh][wh^1]=fa;
    pre[fa]=bh;
    pre[bh]=grand;
    update(fa);
    update(bh);
}

void splay(int bh)
{
    int top=0;
    q[++top]=bh;
    for (int i=bh;!isroot(i);i=pre[i])
        q[++top]=pre[i];
    while (top) push(q[top--]);
    for (int fa;!isroot(bh);rotate(bh))
        if (!isroot(fa=pre[bh]))
            rotate(get(bh)==get(fa) ? fa:bh);
}

void expose(int bh)
{
    int t=0;
    while (bh)
    {
        splay(bh);
        ch[bh][1]=t;
        t=bh;bh=pre[bh];
    }
}

void makeroot(int bh)
{
    expose(bh);
    splay(bh);
    rev[bh]^=1;
}

void link(int x,int y)
{
    makeroot(x);
    pre[x]=y;
    splay(x);
}

void cut(int x,int y)
{
    makeroot(x);
    expose(y);
    splay(y);
    ch[y][0]=pre[x]=0;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        int u;
        scanf("%d",&u);
        if (i+u<=n) link(i,i+u),a[i]=i+u;
        else link(i,n+1),a[i]=n+1;
        size[i]=1;   //初始值不要忘 
    }
    size[n+1]=1;
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        int opt,x,y;
        scanf("%d",&opt);
        if (opt==1)
        {
            scanf("%d",&x);
            x++;  //
            makeroot(n+1);   ///???
            expose(x);
            splay(x);
            printf("%d
",size[ch[x][0]]);
        }
        else 
        {
            scanf("%d%d",&x,&y);
            x++;  //
            cut(x,a[x]);  
            if (x+y<=n) a[x]=x+y;
            else a[x]=n+1;
            link(x,a[x]); 
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673558.html