zoukankan      html  css  js  c++  java
  • 【BZOJ】4764: 弹飞大爷 LCT

    【题意】给定n个数字ai,表示大爷落到i处会被弹飞到i+ai处,弹飞到>n或<1处则落地。m次操作,修改一个ai,或询问大爷落到x处经过几次落地(或-1)。n,m<=10^5,|ai|<=n。

    【算法】Link-Cut Tree

    【题解】n个点n条出边,构成了神奇的基环内向森林。将落地视为第n+1个点,而第n+1个点没有出边,也就是第n+1个点所在的连通子图是一棵树。

    当询问的点所在联通子图是基环内向树时无解,是树时则与第n+1个点的距离就是答案。

    因为要资瓷动态删除和加入边,所以考虑用LCT维护。

    对于一个环,将环上加入的最后一条边隐藏,标记该环上所有点。

    当需要删除时,如果两点间没有连边就删除隐藏边(删除标记也要下传),如果删除的是实边且两点有同一条隐藏边,那么这条隐藏边需要显现。

    询问的时候若x和n+1不在同一个连通子图则无解,否则将x作为中心后access(x),路径长度就是size。

    【实现】首先需要明确LCT标记传递

    1.标记打在splay的根,影响范围有且仅有整棵splay的节点(在程序中规定,标记下传一次后就不再下传)。

    2.lct的操作全部自底向上,只要在rotate和access时上传,splay和findroot时下传,就可以保证标记全部传达到位。

    还需要注意的是,与模板题不同,特殊的题目会在link和cut时出现本不该有的输入,比如x=y的情况要特判掉。

    1.Link(x,y)

    如果两点在同一棵树上,那么新加隐藏边,在这棵树的splay根打标记。否则正常操作。

    2.Cut(x,y)

    将x-y变成主链,如果距离>1(包括x有右儿子的情况!)就删除隐藏边。因为x-y路径其实就是隐藏边所在环,所以可以标记到整个环。

    否则删除实边,然后x和y的隐藏边若相同则显现隐藏边——此时x和y是两棵树,要分别变成所在splay的根后打删除隐藏边的标记。

    主要是将所有要标记的点变成主链再标记。

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    int read(){
        int s=0,t=1;char c;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    const int maxn=200010;
    int t[maxn][2],h[maxn],g[maxn],hu[maxn],hv[maxn],sz[maxn],f[maxn],b[maxn],a[maxn],n;
    bool isroot(int x){return !x||(t[f[x]][0]!=x&&t[f[x]][1]!=x);}
    void up(int x){sz[x]=sz[t[x][0]]+sz[t[x][1]]+1;}
    void down(int x){
        if(g[x]){
            swap(t[x][0],t[x][1]);
            if(t[x][0])g[t[x][0]]^=1;
            if(t[x][1])g[t[x][1]]^=1;
            g[x]=0;
        }
        if(h[x]){// 
            if(t[x][0]){h[t[x][0]]=1;hu[t[x][0]]=hu[x];hv[t[x][0]]=hv[x];}
            if(t[x][1]){h[t[x][1]]=1;hu[t[x][1]]=hu[x];hv[t[x][1]]=hv[x];}
            h[x]=0;
        }
    }
    void rotate(int y){
        int x=f[y];
        int k=y==t[x][0];//
        t[x][!k]=t[y][k];f[t[y][k]]=x;
        if(!isroot(x))t[f[x]][x==t[f[x]][1]]=y;f[y]=f[x];f[x]=y;
        t[y][k]=x;
        up(x);up(y);
    }
    void splay(int x){
        int top=x,tot=1;b[1]=x;
        while(!isroot(top))top=f[top],b[++tot]=top;
        for(int i=tot;i>=1;i--)down(b[i]);
        while(!isroot(x)){
            if(isroot(f[x])){rotate(x);break;}
            int X=x==t[f[x]][1],Y=f[x]==t[f[f[x]]][1];
            if(X^Y)rotate(x),rotate(x);
            else rotate(f[x]),rotate(x);
        }
    }
    void access(int x){
        int y=0;
        while(x){
            splay(x);
            t[x][1]=y;
            up(x);
            y=x;x=f[x];
        }
    }
    void reserve(int x){access(x);splay(x);g[x]^=1;}
    int root(int x){access(x);splay(x);while(t[x][0])x=t[x][0];return x;}
    void link(int x,int y){
        if(x==y)return;
        if(root(x)==root(y)){
            reserve(x);access(y);splay(y);
            h[y]=1;hu[y]=x;hv[y]=y;return;
        }
        reserve(x);f[x]=y;
    }
    void cut(int x,int y){
        if(x==y)return;//
        reserve(x);access(y);splay(y);
        if(t[y][0]!=x||t[x][1]){hu[y]=hv[y]=0;h[y]=1;return;}//
        t[y][0]=f[x]=0;
        if(hu[x]&&hu[x]==hu[y]&&hv[x]==hv[y]){
            int X=hu[x],Y=hv[x];
            reserve(X);reserve(Y);//
            f[X]=Y;
            hu[X]=hu[Y]=hv[X]=hv[Y]=0;
            h[X]=h[Y]=1;
        }
    }
    int query(int x){
        if(root(x)!=root(n+1))return -1;
        reserve(x);access(n+1);splay(x);
        return sz[t[x][1]];
    }
    int main(){
        n=read();int m=read();
        for(int i=1;i<=n+1;i++)sz[i]=1;
        for(int i=1;i<=n;i++){
            a[i]=read()+i;
            if(a[i]>n||a[i]<1)a[i]=n+1;
            link(i,a[i]);
        }
        while(m--){
            int k=read(),x=read();
            if(k==1)printf("%d
    ",query(x));else{
                int y=read()+x;
                cut(x,a[x]);
                if(y>n||y<1)a[x]=n+1;else a[x]=y;
                link(x,a[x]);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    彻底弄懂GMT、UTC、时区和夏令时
    揭秘webpack loader
    揭秘webpack plugin
    封装axios
    webpack优化之玩转代码分割和公共代码提取
    node.js操作数据库之MongoDB+mongoose篇
    GitHub项目徽标
    Java中容易遗漏的小知识点( 一 )(为了和小白一样马上要考试的兄弟准备的,希望小白和大家高过不挂)
    QNX Message Passing,一个让人头秃的 IPC BUG
    【百面】02_模型评估
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7061773.html
Copyright © 2011-2022 走看看