zoukankan      html  css  js  c++  java
  • BZOJ2002:[HNOI2010]弹飞绵羊——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2002

    https://www.luogu.org/problemnew/show/P3203

    某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏。游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞。绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞。为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数。

    因为它的标签有LCT所以应该是用LCT写的。

    因为每个弹射器之间不可能存在环(因为你只能往后跳)所以弹射器和弹飞点(记为n+1)构成了一片森林。

    这样我们先link(i,min(i+k[i],n+1)。

    对于修改操作显然先cut原先的边在按上面方法link即可。

    对于查询我们就是相当于求n+1和i的路径长,先makeroot(n+1),再access(i),这样n+1到i的实边长度即为所求,然后求实链所代表的平衡树大小-1即可。

    (下面为吐槽)

    说实话最开始没想到LCT怎么求两点最短路。

    但是后来一想这不就是access一下之后求实边长度吗。

    再看了洛谷超易懂题解发现实链不就是一棵平衡树吗,求一遍平衡树大小-1不就得了?

    (假装这题很简单)

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cmath>
    using namespace std;
    const int N=2e5+10;
    int n,m,r,k[N],fa[N],tr[N][2],rev[N],q[N],size[N];
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    inline bool get(int x){
        return tr[fa[x]][1]==x;
    }
    inline bool isroot(int x){
        if(!fa[x])return 1;
        return tr[fa[x]][0]!=x&&tr[fa[x]][1]!=x;
    }
    inline void upt(int x){
        size[x]=1;
        if(tr[x][0])size[x]+=size[tr[x][0]];
        if(tr[x][1])size[x]+=size[tr[x][1]];
    }
    inline void pushrev(int x){
        if(!rev[x])return;
        swap(tr[x][0],tr[x][1]);
        if(tr[x][0])rev[tr[x][0]]^=1;
        if(tr[x][1])rev[tr[x][1]]^=1;
        rev[x]=0;
    }
    inline void rotate(int x){
        int y=fa[x],z=fa[y],b=tr[y][0]==x?tr[x][1]:tr[x][0];
        if(z&&!isroot(y))(tr[z][0]==y?tr[z][0]:tr[z][1])=x;
        fa[x]=z;fa[y]=x;b?fa[b]=y:0;
        if(tr[y][0]==x)tr[x][1]=y,tr[y][0]=b;
        else tr[x][0]=y,tr[y][1]=b;
        upt(y);upt(x);
    }
    inline void splay(int x){
        q[r=0]=x;
        for(int y=x;!isroot(y);y=fa[y])q[++r]=fa[y];
        for(int i=r;i>=0;i--)pushrev(q[i]);
        while(!isroot(x)){
        if(!isroot(fa[x]))
            rotate((get(x)==get(fa[x])?fa[x]:x));
        rotate(x);
        }
        upt(x);
    }
    inline void access(int x){
        for(int y=0;x;y=x,x=fa[x]){
        splay(x);tr[x][1]=y;
        if(y)fa[y]=x;
        }
    }
    inline int findroot(int x){
        access(x);splay(x);
        while(pushrev(x),tr[x][0])x=tr[x][0];
        splay(x);
        return x;
    }
    inline void makeroot(int x){
        access(x);splay(x);
        rev[x]^=1;
    }
    inline void link(int x,int y){
        makeroot(x);fa[x]=y;
    }
    inline void cut(int x,int y){
        makeroot(x);access(y);splay(y);
        tr[y][0]=0;fa[x]=0;
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++)
        link(i,min(i+(k[i]=read()),n+1));
        m=read();
        for(int i=1;i<=m;i++){
        int op=read(),j=read()+1;
        if(op==1){
            makeroot(j);access(n+1);splay(n+1);
            printf("%d
    ",size[n+1]-1);
        }else{
            cut(j,min(j+k[j],n+1));
            link(j,min(j+(k[j]=read()),n+1));
        }
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    第 7 章 Neutron
    第 7 章 Neutron
    第 7 章 Neutron
    第 7 章 Neutron
    第 7 章 Neutron
    第 7 章 Neutron
    第 7 章 Neutron
    第 7 章 Neutron
    第 7 章 Neutron
    iOS 屏幕旋转 nav+tabbar+present(网页) 2016
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/8469602.html
Copyright © 2011-2022 走看看