2002: [Hnoi2010]Bounce 弹飞绵羊(分块)

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个装置从左到右分为sqrt(N)段,维护两个数组,f[i][j]表示第I段的第J个位置开始在该段弹多少次,to[i][j]表示第I段的第J个位置弹飞到哪个位置。

每次询问,跑sqrt(N)个段。

每次更新,比如修改i点,只需要更新与i同段且在i左边的f[][]和to[][]

复杂度为N*sqrt(N)

#include 
#include 
#include 
#include 
using namespace std;
#define maxn 200080
#define maxm 508
int f[maxm][maxm];//第I快,第J个位置,跳多少次
int to[maxm][maxm];//第I快,第J个位置,跳到哪个位置
int a[maxn];
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i = 1;i <= n;i++)
            scanf("%d",&a[i]);
        int len = sqrt(double(n))+1;
        int num = n/len;
        if(n%len)   num++;
        for(int i = num;i >= 1;i--)
        {
            for(int j = len;j >= 1;j--)
            {
                int pos = (i-1)*len+j;
                if(pos>n)
                {
                   f[i][j] = 0;
                   to[i][j] = pos;
                   continue;
                }
                if(j+a[pos]<=len)
                {
                    f[i][j] = f[i][j+a[pos]]+1;
                    to[i][j] = to[i][j+a[pos]];
                }
                else
                {
                    f[i][j] = 1;
                    to[i][j] = pos+a[pos];
                }
            }
        }
        int m;
        scanf("%d",&m);
        for(int i = 1;i <= m;i++)
        {
            int ope,p,k;
            scanf("%d%d",&ope,&p);
            p++;
            if(ope == 1)
            {
                int ans = 0;
                while(p <= n)
                {
                    ans += f[(p+len-1)/len][(p%len)?(p%len):len];
                    p = to[(p+len-1)/len][(p%len)?(p%len):len] ;
                }
                printf("%d\n",ans);
            }
            else
            {
                scanf("%d",&k);
                a[p] = k;
                int index = p%len?p%len:len;
                for(int j = index;j >= 1;j--)
                {
                    f[(p+len-1)/len][j] = (j+a[p+j-index]>len?1:(f[(p+len-1)/len][j+a[p+j-index]]+1));
                    to[(p+len-1)/len][j] = (j+a[p+j-index]>len?p+j-index+a[p+j-index] : to[(p+len-1)/len][j+a[p+j-index]]);
                }
            }
        }
    }
    return 0;
}

用LCT也写了一发。
#include 
#include 
#include 
using namespace std;
#define maxn 200080
#define inf 0x3f3f3f3f
int a[maxn],stk[maxn];
int e,n;
struct Link_Cut_Tree
{
    int pre[maxn],ch[maxn][2],flip[maxn];
    int root[maxn],fa[maxn],Size[maxn];
    void init()
    {
        root[0] = Size[0] = ch[0][0] = ch[0][1] = pre[0] = flip[0] = fa[0] = 0;
    }

    void NewNode(int r,int father)
    {
        root[r] = 1;
        Size[r] = 1;
        fa[r] = father;
        ch[r][0] = ch[r][1] = flip[r] = pre[r] = 0;
    }

    void PushTo(int x)
    {
        int rear = 0;
        while(x)
        {
            stk[rear++] = x;
            x = pre[x];
        }
        for(int i = rear-1;i >= 0;i--)
            PushDown(stk[i]);
    }

    void PushDown(int x)
    {
        if(flip[x])
        {
            Update_Rev(ch[x][0]);
            Update_Rev(ch[x][1]);
            flip[x] = 0;
        }
    }

    void PushUp(int x)
    {
        int l = ch[x][0],r = ch[x][1];
        Size[x] = Size[l] + Size[r] + 1;
    }

    void Update_Rev(int x)
    {
        swap(ch[x][0],ch[x][1]);
        flip[x] ^= 1;
    }

    void Rotate(int x,int kind)
    {
        int y = pre[x];
        ch[y][!kind] = ch[x][kind];
        if(ch[x][kind])
            pre[ch[x][kind]] = y;
        if(pre[y])
            ch[pre[y]][ch[pre[y]][1]==y] = x;
        pre[x] = pre[y];
        ch[x][kind] = y;
        pre[y] = x;
        PushUp(y);

        if(root[y])
        {
            root[y] = 0;
            root[x] = 1;
            fa[x] = fa[y];
            fa[y] = 0;
        }
    }

    void Splay(int r)
    {
        PushTo(r);
        while(pre[r] != 0)
        {
            int y = pre[r],z = pre[y];
            if(z == 0)
            {
                Rotate(r,ch[y][0]==r);
            }
            else
            {
                int kind = (ch[z][0] == y);
                if(ch[y][kind] == r)
                {
                    Rotate(r,!kind);
                    Rotate(r,kind);
                }
                else
                {
                    Rotate(y,kind);
                    Rotate(r,kind);
                }
            }
        }
        PushUp(r);
    }

    int Access(int x)
    {
        int c = 0;
        while(x)
        {
            Splay(x);
            if(ch[x][1])
            {
                fa[ch[x][1]] = x;
                Is_Root(ch[x][1]);
            }
            ch[x][1] = c;
            if(c)
            {
                pre[c] = x;
                fa[c] = 0;
            }
            root[c] = 0;
            c = x;  x = fa[x];
        }
        return c;
    }

    void Make_Root(int x)
    {
        Access(x);
        Splay(x);
        Update_Rev(x);
    }

    void Is_Root(int x)
    {
        root[x] = 1;
        pre[x] = 0;
    }

    void Link(int u,int v)
    {
        if(u == v)  return;
        Make_Root(u);
        Access(v);
        Splay(v);
        if(pre[u] == 0) fa[u] = v;
    }

    void Cut(int u,int v)
    {
        Make_Root(u);
        Access(v);
        Splay(v);
        if(pre[u])
        {
            if(ch[v][0])
                Is_Root(ch[v][0]);
            fa[ch[v][0]] = 0;
            ch[v][0] = 0;
            Is_Root(v);
            fa[v] = 0;
            PushUp(v);
        }
    }

    int Query(int u)
    {
        Make_Root(n+1);
        Access(u);
        Splay(u);
        return Size[ch[u][0]];
    }

    void solve()
    {
        for(int i = 1;i <= n;i++)
            scanf("%d",&a[i]);
        int q;
        scanf("%d",&q);
        init();
        NewNode(n+1,0);
        for(int i = n;i >= 1;i--)
        {
            int u = i,v = i+a[i] > n? n+1:i+a[i];
            NewNode(u,v);
        }
        while(q--)
        {
            int ope,pos,k;
            scanf("%d%d",&ope,&pos);
            pos++;
            if(ope == 1)
            {
                printf("%d\n",Query(pos));
            }
            else
            {
                scanf("%d",&k);
                int apre = a[pos]+pos>n?n+1:a[pos]+pos;
                Cut(pos,apre);
                a[pos] = k;
                int anow = a[pos]+pos>n?n+1:a[pos]+pos;
                Link(pos,anow);
            }
        }
    }
}lct;

int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(scanf("%d",&n)!=EOF)
    {
        lct.solve();
    }
}


你可能感兴趣的:(分块,Link-Cut-Tree)