BZOJ-2002 弹飞绵羊 Link-Cut-Tree (分块)

2002: [Hnoi2010]Bounce 弹飞绵羊
Time Limit: 10 Sec Memory Limit: 259 MB
Submit: 6801 Solved: 3573
[Submit][Status][Discuss]

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

HINT

Source

套LCT即可,需要维护子树的size,弹的时候处理好即可
分块也可做,等我搞定分块,再来搞搞

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define N 200100
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

int f[N],son[N][2],tmp[N];bool rev[N];
int next[N],size[N];

bool isroot(int x)
{
    return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;
}

void rev1(int x)
{
    if(!x) return;
    swap(son[x][0],son[x][1]);
    rev[x]^=1;
}

void pb(int x)
{
    if(rev[x])
        rev1(son[x][0]),rev1(son[x][1]),rev[x]=0;
}

void updata(int x)
{
    size[x]=size[son[x][0]]+size[son[x][1]]+1;
}

void rotate(int x)
{
    int y=f[x],w=son[y][1]==x;
    son[y][w]=son[x][w^1];
    if(son[x][w^1]) f[son[x][w^1]]=y;
    if(f[y])
        {
            int z=f[y];
            if(son[z][0]==y)son[z][0]=x;
                else if(son[z][1]==y)son[z][1]=x;
        }
    f[x]=f[y];f[y]=x;
    son[x][w^1]=y;
    updata(x);updata(y);
}

void splay(int x)
{
    int s=1,i=x,y;tmp[1]=i;
    while(!isroot(i)) tmp[++s]=i=f[i];
    while(s) pb(tmp[s--]);
    while(!isroot(x))
        {
            y=f[x];
            if(!isroot(y))
                {
                    if((son[f[y]][0]==y)^(son[y][0]==x))
                    rotate(x);  else  rotate(y);
                }
            rotate(x);
        }
}

void access(int x)
{
    for(int y=0;x;y=x,x=f[x])
        splay(x),son[x][1]=y;
}

void makeroot(int x)
{
    access(x);splay(x);rev1(x);
}

void link(int x,int y)
{
    makeroot(x);
    f[x]=y;
    access(x);
}

void cutf(int x)
{
    access(x);splay(x);
    f[son[x][0]]=0;son[x][0]=0;
}
void cut(int x,int y)
{
    makeroot(x);cutf(y);
}

int n,m;
int main()
{
    n=read();
    for (int i=1; i<=n; i++)
        {
            int x=read();
            size[x]=1;
            f[i]=x+i;if (f[i]>n+1) f[i]=n+1;
            next[i]=f[i];
        }
        size[n+1]=1;
    m=read();
    for (int i=1; i<=m; i++)
        {
            int com=read();
            if (com==1)
                {
                    int x=read();
                    makeroot(n+1);
                    access(x+1);splay(x+1);
                    printf("%d
",size[son[x+1][0]]);
                }
            else
                {
                    int x=read(),y=read();
                    int temp=min(n+1,x+y+1);
                    cut(x+1,next[x+1]);link(x+1,temp);
                    next[x+1]=temp;
                }
        }
    return 0;
}
原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346168.html