BZOJ2002:Bounce 弹飞绵羊(LCT)

某天,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

思路:树状结构,改变权值其实是删一条边和加一条边,所以转化为LCT题。

优化:开始建树(原树,一共N条边,根为N+1)的时候,由于原树的虚拟的,我们不一定要把N条边都Link,而是可以直接记录fa即可。

当然还可以用分块做。但是没有LCT直观。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=300010;
void read(int &x){
    char c=getchar(); x=0;
    for(;c>'9'||c<'0';c=getchar());
    for(;c<='9'&&c>='0';c=getchar()) x=(x<<3)+(x<<1)+c-'0';
}
struct LCT
{
    int sum[maxn],rev[maxn],ch[maxn][2],fa[maxn],stc[maxn],top;
    int isroot(int x){
        return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
    }
    int get(int x){
        return ch[fa[x]][1]==x;
    }
    void pushdown(int x)
    {
        if(!rev[x]||!x) return ;
        swap(ch[x][0],ch[x][1]);
        if(ch[x][0]) rev[ch[x][0]]^=1; 
        if(ch[x][1]) rev[ch[x][1]]^=1; 
        rev[x]=0;
    }
    void pushup(int x)
    {
        sum[x]=1;
        if(ch[x][0]) sum[x]+=sum[ch[x][0]];
        if(ch[x][1]) sum[x]+=sum[ch[x][1]];
    }
    void rotate(int x)
    {
        int old=fa[x],fold=fa[old],opt=get(x);
        if(!isroot(old)) ch[fold][get(old)]=x;
        fa[x]=fold;
        ch[old][opt]=ch[x][opt^1]; fa[ch[old][opt]]=old;
        ch[x][opt^1]=old; fa[old]=x; 
        pushup(old); pushup(x);
    }
    void splay(int x)
    {
        int top=0; stc[++top]=x;
        for(int i=x;!isroot(i);i=fa[i]) stc[++top]=fa[i];
        for(int i=top;i;i--) pushdown(stc[i]);
        for(int f;!isroot(x);rotate(x)){
            if(!isroot(f=fa[x]))
              rotate(get(x)==get(f)?f:x);
        }        
    }
    void access(int x)
    {
        int rson=0;
        for(;x;rson=x,x=fa[x]){
            splay(x);
            ch[x][1]=rson;
            pushup(x);
        }
    }
    int find(int x){ access(x); splay(x); while(ch[x][0]) x=ch[x][0]; return x;}
    int query(int x,int y) { make_root(x); access(y);  splay(y); return sum[y]-1; }
    void make_root(int x) { access(x); splay(x); rev[x]^=1; }
    void link(int x,int y) { make_root(x); fa[x]=y; splay(x); }
    void cut(int x,int y) { make_root(x); access(y); splay(y); fa[x]=ch[y][0]=0; }    
    
}S;
int a[maxn];
int main()
{
    int N,M,Q,opt,x,y,i;
    scanf("%d",&N);
    for(i=1;i<=N;i++){
        read(a[i]);
        S.link(i,min(N+1,i+a[i]));
    }
    scanf("%d",&Q);
    while(Q--){
        scanf("%d",&opt);
        if(opt==1){
            read(x); x++;
            printf("%d\n",S.query(N+1,x));
        }
        else{
            read(x); read(y); x++;
            S.cut(x,min(N+1,x+a[x])); 
            a[x]=y; 
            S.link(x,min(N+1,x+a[x]));
        }
    }
    return 0;
}

 

posted @ 2018-04-03 23:09  nimphy  阅读(305)  评论(0编辑  收藏