• HDU 5967 小R与手机(动态树)


    【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=5967

    【题目大意】

      给出一张图,每个点仅连一条有向边,或者不连,
      要求查询在可更改有向边的情况每个点通过有向边最终能到的终点,
      如果是个环则输出-1

    【题解】

      我们用lct维护,同时在每棵树根结点的位置标记环,
      因为出现环一定在根节点,否则的话只是换直接父节点而不成环,
      对于换直接父节点的操作,我们看该树的根是否有标记,
      如果有则需要在cutf之后重新构建这棵树的根,
      如果换的父节点为自己的子节点,那么就另成一棵树并标记环,

    【代码】

    #include <cstdio>
    #include <cstring>
    #include <algorithm> 
    using namespace std;
    const int N=200010;
    namespace Link_Cut_Tree{
        int f[N],son[N][2],val[N],sum[N],tmp[N],Xor[N];bool rev[N];
        void Initialize(){
            memset(f,0,sizeof(f));
            memset(son,0,sizeof(son));
            memset(val,0,sizeof(val));
            memset(rev,0,sizeof(rev));
        } 
        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 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;
        }
        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;}
        // 查询x所在的树的根
        int root(int x){access(x);splay(x);while(son[x][0])x=son[x][0];return x;}
        // 使x成为根
        void makeroot(int x){access(x);splay(x);rev1(x);}
        // 将x和y所属树合并
        void link(int x,int y){makeroot(x);f[x]=y;access(x);}
        // 将x和其父节点分开 
        void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;}
        // 将边x-y切断
        void cut(int x,int y){makeroot(x);cutf(y);}
        // 查询x到y的链和
        int ask(int x,int y){makeroot(x);access(y);splay(y);return sum[y];}
        // 计算x到y的xor和
        int xorsum(int x,int y){makeroot(x);access(y);splay(y);return Xor[y];}
        // 查询节点到根的距离
        int query(int x){access(x);splay(x);return sum[x];}
        // 将x为下标的值改为y
        int change(int x,int y){makeroot(x);val[x]=y;}
        // 将x的父亲改为y
        int changef(int x,int y){cutf(x);f[x]=y;}
    }
    int mark[N];
    void Link(int x,int y){
    	using namespace Link_Cut_Tree; 
        int rx=root(x);
        if(rx==x)mark[x]=0;
        else cutf(x);
        if(mark[rx]&&root(mark[rx])!=rx){
            changef(rx,mark[rx]);
            mark[rx]=0;
        }if(root(y)==x)mark[x]=y;
        else changef(x,y);
    }
    int n,m,op,x;
    int main(){
        scanf("%d%d",&n,&m);
        using namespace Link_Cut_Tree;
        Initialize();
        for(int i=1;i<=n;i++){
            scanf("%d",&x);
            if(x)Link(i,x);
        }
        while(m--){
            scanf("%d%d",&op,&x);
            if(op==2){
                x=root(x);
                printf("%d
    ",mark[x]==0?x:-1);
            }else{
                int y;
                scanf("%d",&y);
                Link(x,y);
            }
        }return 0;
    }
  • 相关阅读:
    Oracle中常用的to_Char用法详解(有FMT的详细列表)
    js底层ajax
    MD5加密
    "<br />"和 "\r\n" 这两者有什么区别??
    SqlHelper类
    treeview实例
    在标题栏显示新消息提示,很多公司项目中用到这个方法
    SQL一些时间格式的转换
    用SQL语句添加删除修改字段、一些表与字段的基本操作、数据库备份等
    SQL Server触发器创建、删除、修改、查看示例步骤
  • 原文地址:https://www.cnblogs.com/forever97/p/hdu5967.html
Copyright © 2020-2023  润新知