zoukankan      html  css  js  c++  java
  • 圣战 [奇环, 树上差分]

    圣战


    color{red}{正解部分}

    xxyy 之间有敌对关系, 则在 xxyy 之间连一条边, 依此建出一个图,

    当图中存在 奇环 时, 无法完成二染色, 说明无法划分为 22 个合法的阵营,

    现在目的就是删去其中一条边, 使得图中不存在 奇环, 自然而然的, 删去的边是所有 奇环,
    所以现在需要求出哪些边是 所有奇环 .

    于是有个最初的做法:
    利用 返祖边 配合 树上差分 找出图中的每个点被 奇环 覆盖的次数,
    若两个相连的点都被所有奇环覆盖, 说明这两个点之间的边被所有奇环覆盖, 删去这条边 .

    bug但是这样仍然有bug:
    当删去某条边时, 若这条边在 偶环奇环 中, 则删边后关于这条边的 奇环偶环, 偶环奇环,
    而新的 奇环 和 新的 偶环 组合会形成新的 奇环, 这就不合法了 .

    所以:
    当一条边被所有 奇环 覆盖, 且不被任何一个 偶环 覆盖时, 该边删去后 存在合法的方案 将图分为两个不同的阵营 .


    color{red}{实现部分}

    • 当只存在一个 奇环 时, 返祖边 也可以作为计入答案, 否则 返祖边 不可能计入答案 .
    #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 = 1e6 + 10;
    
    int N;
    int M;
    int cnt;
    int num0;
    int Tmp_1;
    int Fa[maxn];
    int dep[maxn];
    int head[maxn];
    int Cf[maxn][2];
    int Fa_edge[maxn];
    
    bool vis[maxn];
    
    struct Edge{ int nxt, to, w; } edge[maxn << 1];
    
    void Add(int from, int to, int w){
            edge[++ num0] = (Edge){ head[from], to, w };
            head[from] = num0;
    }
    
    void DFS(int k, int fa){
            vis[k] = 1, dep[k] = dep[fa] + 1, Fa[k] = fa;
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa || vis[to]) continue ;
                    Fa_edge[to] = edge[i].w; DFS(to, k);
            }
    }
    
    void DFS_2(int k, int fa){
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ;
                    if(Fa[to] == k) DFS_2(to, k);
                    else if(dep[to] < dep[k] && (dep[to]-dep[k] & 1)) Cf[k][1] ++, Cf[to][1] --;
                    else if(dep[to] < dep[k]) cnt ++, Cf[k][0] ++, Cf[to][0] --, Tmp_1 = edge[i].w;
            }
    }
    
    void DFS_3(int k, int fa){
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa || Fa[to] != k) continue ;
                    DFS_3(to, k); Cf[k][0] += Cf[to][0], Cf[k][1] += Cf[to][1];
            }
    }
    
    int main(){
            N = read(), M = read();
            for(reg int i = 1; i <= M; i ++){
                    int u = read(), v = read();
                    Add(u, v, i), Add(v, u, i);
            }
            for(reg int i = 1; i <= N; i ++) if(!vis[i]) DFS(i, 0);
            for(reg int i = 1; i <= N; i ++)
                    if(!Fa[i]) DFS_2(i, 0), DFS_3(i, 0);
    
            int Ans_1 = 0, Ans_2 = 0;
    
            if(!cnt){
                    Ans_1 = M;
                    for(reg int i = 1; i <= M; i ++) Ans_2 ^= i; 
                    printf("%d
    %d
    ", Ans_1, Ans_2);
                    return 0;
            }
            
            if(cnt == 1) Ans_1 = 1, Ans_2 = Tmp_1;
    
            for(reg int i = 1; i <= N; i ++) 
                    if(Cf[i][0]==cnt && !Cf[i][1]) Ans_1 ++, Ans_2 ^= Fa_edge[i];
    
            printf("%d
    %d
    ", Ans_1, Ans_2);
            return 0;
    }
    
  • 相关阅读:
    操作集锦
    大吉大利(算贡献)
    96. 奇怪的汉诺塔
    P760通天之汉诺塔
    First Last Sorting
    9.12小结
    day_06
    day_05作业
    day_05
    day_04
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822485.html
Copyright © 2011-2022 走看看