1. 程式人生 > >BZOJ2002[Hnoi2010]彈飛綿羊

BZOJ2002[Hnoi2010]彈飛綿羊

開始 con zoj pushd spa link 100% aps lin

題目描述

某天,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。對於20%的數據n,m<=10000,對於100%的數據n<=200000,m<=100000

輸出

對於每個i=1的情況,你都要輸出一個需要的步數,占一行。

樣例輸入

4
1 2 1 1
3
1 1
2 1 1
1 1

樣例輸出

2
3
當跳過n之後就被彈飛,那麽可以建一個虛點n+1,將彈飛看作彈到n+1這個節點上。 i會被彈到i+ki號節點上,那麽直接將i號節點和i+ki號節點連上就好了。 修改直接斷開原來連的邊,重新連接一條邊,LCT維護就好了。 因為每個點只會連接一個比它編號大的點,所以最後形成了一棵樹,每次詢問直接查詢j和n+1路徑上的節點數-1即可。
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int x,y;
int opt;
int s[200020][2];
int f[200020];
int r[200020];
int st[200020];
int size[200020];
int dis[200020];
int get(int rt)
{
    return rt==s[f[rt]][1];
}
void pushup(int rt)
{
    size[rt]=size[s[rt][0]]+size[s[rt][1]]+1;
}
void pushdown(int rt)
{
    if(r[rt])
    {
        r[s[rt][0]]^=1;
        r[s[rt][1]]^=1;
        r[rt]^=1;
        swap(s[rt][0],s[rt][1]);
    }
}
int is_root(int rt)
{
    return rt!=s[f[rt]][0]&&rt!=s[f[rt]][1];
}
void rotate(int rt)
{
    int fa=f[rt];
    int anc=f[fa];
    int k=get(rt);
    if(!is_root(fa))
    {
        s[anc][get(fa)]=rt;
    }
    s[fa][k]=s[rt][k^1];
    f[s[fa][k]]=fa;
    s[rt][k^1]=fa;
    f[fa]=rt;
    f[rt]=anc;
    pushup(fa);
    pushup(rt);
}
void splay(int rt)
{
    int top=0;
    st[++top]=rt;
    for(int i=rt;!is_root(i);i=f[i])
    {
        st[++top]=f[i];
    }
    for(int i=top;i>=1;i--)
    {
        pushdown(st[i]);
    }
    for(int fa;!is_root(rt);rotate(rt))
    {
        if(!is_root(fa=f[rt]))
        {
            rotate(get(fa)==get(rt)?fa:rt);
        }
    }
}
void access(int rt)
{
    for(int x=0;rt;x=rt,rt=f[rt])
    {
        splay(rt);
        s[rt][1]=x;
        pushup(rt);
    }
}
void reverse(int rt)
{
    access(rt);
    splay(rt);
    r[rt]^=1;
}
int find(int rt)
{
    access(rt);
    splay(rt);
    while(s[rt][0])
    {
        rt=s[rt][0];
    }
    return rt;
}
void link(int x,int y)
{
    reverse(x);
    f[x]=y;
}
void cut(int x,int y)
{
    reverse(x);
    access(y);
    splay(y);
    s[y][0]=f[x]=0;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n+1;i++)
    {
        size[i]=1;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        dis[i]=x;
        if(i+x<=n)
        {
            link(i,i+x);
        }
        else
        {
            link(i,n+1);
        }
    }
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d",&x);
            x++;
            reverse(x);
            access(n+1);
            splay(n+1);
            printf("%d\n",size[n+1]-1);
        }
        else
        {
            scanf("%d%d",&x,&y);
            x++;
            if(x+dis[x]<=n)
            {
                cut(x,x+dis[x]);
            }
            else
            {
                cut(x,n+1);
            }
            dis[x]=y;
            if(x+dis[x]<=n)
            {
                link(x,x+dis[x]);
            }
            else
            {
                link(x,n+1);
            }
        }
    }
}

BZOJ2002[Hnoi2010]彈飛綿羊