• HNOI2010 弹飞绵羊


    codevs 2333 弹飞绵羊

    http://codevs.cn/problem/2333/

    2010年省队选拔赛湖南

    题目描述 Description

    Lostmonkey发明了一种超级反弹装置。为了在绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿一条直线摆放 n个反弹装置,并按从前往后的方式将反弹装置依次编号为 0 到 n-1,对 0≤i≤n-1,为第 i 个反弹装置设定了初始弹力系数 ki,当绵羊落到第 i 个反弹装置上时,它将被往后弹出 ki 步,即落到第 i+ki 个反弹装置上,若不存在第i+ki个反弹装置,则绵羊被弹飞。绵羊想知道: 从第i个反弹装置开始, 它被弹出几次 (含被弹飞的那次)后会被弹飞。为使游戏更有趣,Lostmonkey 还可以修改某个反弹装置的弹力系数,但任何时候弹力系数均为正整数。

    输入描述 Input Description

    输入文件第一行是一个整数n,表示地上摆放n个反弹装置,输入文件第二行是用空格隔开的n个正整数k0,k1,…,kn-1,分别表示n个反弹装置的初始弹力系数。输入文件第三行是一个正整数m,表示后面还有m行输入数据。接下来的m行,每行至少有用空格隔开的两个整数i和j,若i=1,则你要输出从第j个反弹装置开始,被弹出几次后会被弹飞;若i=2,则该行有用空格隔开的三个整数i,j和k,表示第j个反弹装置的弹力系数被修改为k。

    输出描述 Output Description

    包含的行数等于输入文件最后m行中i=1的行数。第h行输出一个整数,表示对输入中给出的第h个求弹出次数的问题,基于n个反弹装置当时的弹力系数,求出的弹出次数。

    样例输入 Sample Input


    1 2 1 1

    1 1 
    2 1 1 
    1 1

    样例输出 Sample Output


    3

    数据范围及提示 Data Size & Hint

    输入的数据保证20%的数据满足n,m≤10000。100%的数据满足n≤200000,m≤100000

    用LCT维护子树大小

    每弹跳一次,树中+1个节点(本次弹跳终点),这样弹跳次数就转化为了子树的大小

    反弹装置从0——n-1,为了方便处理,全体后移一位

    最初,对于每个反弹装置i,由i向min(n+1,i+k[i])连一条边,i指向min(n+1,i+k[i]) 

    即这里从树根到往下是弹跳的逆过程

    这样的好处是固定了弹飞点

    #include<cstdio>
    #include<algorithm>
    #define N 200010
    using namespace std;
    int fa[N],ch[N][2],tag[N],siz[N],k[N],st[N],next[N];
    int n,m;
    inline void up(int x)
    {
        siz[x]=siz[ch[x][1]]+siz[ch[x][0]]+1;
    }
    inline void down(int x)
    {
        if(tag[x])
        {
            tag[x]^=1;tag[ch[x][0]]^=1;tag[ch[x][1]]^=1;
            swap(ch[x][0],ch[x][1]);
        }
    }
    inline bool isroot(int x)
    {
        return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; 
    }
    inline void rotate(int x)
    {
        int y=fa[x],z=fa[y],l,r=0;
        if(ch[y][0]==x) l=0; else l=1;
        r=l^1;
        if(!isroot(y))
        {
            if(ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x;
        } 
        ch[y][l]=ch[x][r];ch[x][r]=y;
        fa[y]=x;fa[ch[y][l]]=y;fa[x]=z;
        up(y);
    }
    inline void splay(int x)
    {
        int t=0;st[++t]=x;
        for(int i=x;!isroot(i);i=fa[i]) st[++t]=fa[i];
        for(int i=t;i;i--) down(st[i]);
        while(!isroot(x))
        {
            int y=fa[x],z=fa[y];
            if(!isroot(y))
            {
                if(ch[y][0]==x^ch[z][0]==y) rotate(x);
                else rotate(y); 
            }
            rotate(x);
            up(x);
        }
    }
    inline void access(int x)
    {
        int t=0;
        while(x)
        {
            splay(x);
            ch[x][1]=t;
            t=x;x=fa[x];
        }
    }
    inline void make_root(int x)
    {
        access(x);
        splay(x);
        tag[x]^=1;
    }
    inline void link(int x,int y)
    {
        make_root(x);
        fa[x]=y;
        splay(x);
    }
    inline void cut(int x,int y)
    {
        make_root(y);
        access(x);
        splay(x);
        ch[x][0]=fa[y]=0;
    } 
    int main()
    {
        scanf("%d",&n);
        int x;
        for(int i=1;i<=n;i++) 
        {
            scanf("%d",&x);
            fa[i]=x+i;siz[i]=1;
            if(fa[i]>n+1)fa[i]=n+1;
            next[i]=fa[i];
        }
        siz[n+1]=1;
        int p,y;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&p);
            if(p==1)
            {
                scanf("%d",&x);
                make_root(n+1);
                x++;
                access(x);splay(x);printf("%d
    ",siz[ch[x][0]]);
            } 
            
            else 
            {
                scanf("%d%d",&x,&y);x++;
                int t=min(n+1,x+y);
                cut(x,next[x]);link(x,t);next[x]=t;
            }
        } 
    }
  • 相关阅读:
    net5:动态修改内存中的站点地图节点
    手动创建DataTable并绑定gridview
    文件转换成二进制流及二进制流转换成文件
    XML 增、删、改和查的实例【转】
    免费CSS鼠标样式代码大全
    C#连接数据库SQL(2005)
    关于hibernate4.3版本之后org.hibernate.service.ServiceRegistryBuilder被弃用
    史上最全的Maven Pom文件标签详解
    Readme.MD 例子
    GitHub中README.md文件的编辑和使用
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6445164.html
Copyright © 2020-2023  润新知