• P5157 The Cow Gathering [拓扑排序/树上差分]


    The Cow GatheringThe Cow Gathering


    Descriptionmathcal{Description}

    给定 NN 个节点的树, 有 MM 条限制条件 : aia_ibib_i 先删除.
    请输出 所有节点能否最后被删除.


    Solution1mathcal{Solution_1}

    :color{red}{步骤:}

    1. 找到任意一个满足条件的点 rootroot
    2. 统计答案

     root:color{blue}{找 root:}

    • aia_ibib_i 连有向边
    • color{black}{拓扑排序}
    • 若存在 , 说明无解,
    • 否则取出 color{purple}{拓扑序最大的节点}, 即为一个满足条件的节点 rootroot.

    :color{blue}{统计答案:}

    rootroot 为根建树 :

    对于一颗子树, 设该节点为 ss,

    :分两种情况讨论:

    1. scolor{red}{s} 有连出去的 有向边.

      scolor{red}{s} 为根节点的子树所有节点全部不能作为最后一个节点出去

      :color{purple}理由: 不明

    2. scolor{red}{s} 没有连出去的 有向边 .

      不操作


    Solution2mathcal{Solution_2}

    使用 树上差分, 以 dfn[]dfn[] 为下标建立 差分数组,

    对于 ai,bia_i, b_i, 同样 aia_ibib_i 连一条有向边,

    先使用 拓扑排序 判环, 若有环说明 无解, 否则 :

    此时分为三种情况 :

    1. aabb 上方
    2. bbaa 上方
    3. aabb 拥有 最近公共祖先

    对于 2情况23情况3, 直接将 dfn[a], dfn[a]+size[a]dfn[a], dfn[a]+size[a] 进行差分操作,
    对于 1情况1, 记 全局数组 flagflag, 将 flag++flag++,

    bb 跳到 aa 的正下方后 !!

    dfn[b], dfn[b]+1dfn[b], dfn[b]+1 进行 反差分操作.

    最后根据 差分数组 统计答案.


    Codemathcal{Code}

    #include<bits/stdc++.h>
    #define reg register
    
    int read(){
            char c;
            int s = 0, flag = 1;
            while((c=getchar()) && !isdigit(c))
                    if(c == '-'){ flag = -1, c = getchar(); break ; }
            while(isdigit(c)) s = s*10 + c-'0', c = getchar();
            return s * flag;
    }
    
    const int maxn = 100005;
    
    int N;
    int M;
    int num0;
    int tot;
    int flag;
    int C[maxn];
    int rd[maxn];
    int dfn[maxn];
    int dep[maxn];
    int size[maxn];
    int head[maxn];
    int Fk[maxn][20];
    
    bool Used[maxn];
    
    struct Edge{ int nxt, to; } edge[maxn<<2];
    void Add(int from, int to){
            edge[++ num0] = (Edge){ head[from], to };
            head[from] = num0;
    }
    
    void DFS(int k, int fa){
            dfn[k] = ++ tot;
            dep[k] = dep[fa] + 1;
            size[k] = 1;
            for(reg int i = 1; i <= 19; i ++) Fk[k][i] = Fk[Fk[k][i-1]][i-1];
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ;
                    Fk[to][0] = k;
                    DFS(to, k);
                    size[k] += size[to];
            }
    }
    
    int LCA(int a, int b){
            if(dep[a] < dep[b]) std::swap(a, b);
            for(reg int i = 19; i >= 0; i --)
                    if(dep[Fk[a][i]] >= dep[b]) a = Fk[a][i];
            if(a == b) return a;
            for(reg int i = 19; i >= 0; i --)
                    if(Fk[a][i] != Fk[b][i]) a = Fk[a][i], b = Fk[b][i];
            return Fk[a][0];
    }
    
    bool chk(){
            tot = 0;
            std::queue <int> Q;
            for(int i = 1; i <= N; i ++)
                    if(rd[i] == 1) Q.push(i), rd[i] --;
            while(!Q.empty()){
                    int ft = Q.front(); Q.pop();
                    tot ++, rd[ft] --;
                    for(reg int i = head[ft]; i; i = edge[i].nxt){
                            int to = edge[i].to;
                            if(-- rd[to] == 1) Q.push(to);
                    }
            }
            if(tot < N) return 0;
            return 1;
    }
    
    int jump(int a, int b){
            for(reg int i = 19; i >= 0; i --)
                    if(dep[Fk[a][i]] > dep[b]) a = Fk[a][i];
            return a;
    }
    
    int main(){
            freopen("visit.in", "r", stdin);
            freopen("visit.out", "w", stdout);
            N = read();
            M = read();
            for(reg int i = 1; i < N; i ++){
                    int x = read(), y = read();
                    Add(x, y), Add(y, x);
                    rd[x] ++, rd[y] ++;
            }
            DFS(1, 0);
            for(reg int i = 1; i <= M; i ++){
                    int a = read(), b = read();
                    Add(a, b), rd[b] ++;
                    int lca = LCA(a, b);
                    if(lca == a){  // a up b
                            int t = jump(b, a);
                            C[dfn[t]] --, C[dfn[t]+size[t]] ++;
                            flag ++;
                    }else if(lca != a && lca != b){ // a ^ b
                            C[dfn[a]] ++;
                            C[dfn[a]+size[a]] --;
                    }else if(lca == b){ // b up a
                            C[dfn[a]] ++;
                            C[dfn[a]+size[a]] --;
                    }
            }
            if(!chk()){
                    for(reg int i = 1; i <= N; i ++) printf("0
    ");
                    return 0;
            }else{
                    for(reg int i = 1; i <= N; i ++) C[i] += C[i-1];
                    for(reg int i = 1; i <= N; i ++)
                            if(C[dfn[i]]+flag > 0) printf("0
    ");
                            else printf("1
    ");
            }
            return 0;
    }
    
  • 相关阅读:
    oracle循环语句
    解决使用Properties读取中文乱码问题
    oracle常用& to_date()怎么转换带am pm的时间格式
    distinct 多列详解
    javascript中遍历EL表达式List集合中的值
    最近一段时间代码汇总
    JAVA基础之对象的初始化
    求解圆圈中最后剩下的数字
    删除有序链表中的重复结点
    构造二叉树,并求解树的高度
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822607.html
Copyright © 2020-2023  润新知