zoukankan      html  css  js  c++  java
  • 【BZOJ】P4238 电压

    生成树

    题目链接

    显然,如果是一棵树的话,那么任意拿一条边都是没关系的。

    因此,我们先在图上随便生成一棵树,由于这是无向图,因此非树边只有返祖边。

    那么,我们考虑非树边形成的环的奇偶性(即环上点数量的奇偶性)。

    1.对于奇环:

    不难发现,奇环上我们必须选一条边。换言之,我们选的边必须在奇环上。

    2.对于偶环:

    也不难发现,偶环上是不能选边的。

    那么,本题就有大致思路了:

    1.先构建一棵树

    2.判断非树边构成的环的奇偶性,如果是奇环,利用树上差分把非树边两端在树上的路径上的边都+1;否则都-1,同时统计奇环数量cnt

    3.遍历整棵树,判断一条边被加过的次数是否为cnt,若符合,则将ans++

    注意:如果只有一个奇环,那么那条形成奇环的非树边也是可以选的,因此要将ans++

    代码:

    #include<bits/stdc++.h>
    #define MAXN 200010
    using namespace std;
    int n,m,tot,head[MAXN],ST[MAXN],ED[MAXN],deep[MAXN],pre[MAXN][20],lg[MAXN],cnt[MAXN],sum,ans;
    bool vis[MAXN],edge[MAXN*2],mark[MAXN];
    struct node {
        int ed,id,last;
    } G[MAXN*4];
    void Add(int st,int ed,int id) {
        tot++;
        G[tot]=node {ed,id,head[st]};
        head[st]=tot;
    }
    vector<int> Tr[MAXN];
    void DFS(int x,int fa) {
        deep[x]=deep[fa]+1;
        pre[x][0]=fa;
        for(int i=1;(1<<i)<=deep[x];i++)pre[x][i]=pre[pre[x][i-1]][i-1];
        vis[x]=true;
        for(int i=head[x]; ~i; i=G[i].last) {
            int t=G[i].ed;
            if(t==fa)continue;
            if(vis[t])continue;
            Tr[x].push_back(t);
            Tr[t].push_back(x);
            edge[G[i].id]=true;
            DFS(t,x);
        }
    }
    int LCA(int x,int y){
        if(deep[x]<deep[y])swap(x,y);
        while(deep[x]>deep[y])x=pre[x][lg[deep[x]-deep[y]]-1];
        if(x==y)return x;
        for(int i=lg[deep[x]]-1;i>=0;i--){
            if(pre[x][i]==pre[y][i])continue;
            x=pre[x][i],y=pre[y][i];
        }
        return pre[x][0];
    }
    void solve(int x,int fa){
        vis[x]=true;
        for(int i=0;i<Tr[x].size();i++){
            int t=Tr[x][i];
            if(t==fa)continue;
            solve(t,x);
            cnt[x]+=cnt[t];
        }
    }
    int main() {
        for(int i=1;i<=MAXN-10;i++)lg[i]=lg[i-1]+((1<<lg[i-1])==i);
        memset(head,-1,sizeof(head));
        scanf("%d %d",&n,&m);
        for(int i=1; i<=m; i++) {
            int x,y;
            scanf("%d %d",&x,&y);
            Add(x,y,i);
            Add(y,x,i);
        }
        tot=0;
        for(int i=1;i<=n;i++){
            if(vis[i])continue;
            DFS(i,0);
        }
        for(int i=1;i<=n;i++){
            for(int j=head[i];~j;j=G[j].last){
                int t=G[j].ed,id=G[j].id;
                if(edge[id])continue;
                int st=i,ed=t;
                if(deep[st]<deep[ed])swap(st,ed);
                ST[++tot]=st,ED[tot]=ed,edge[id]=true;
            }
        }
        for(int i=1;i<=tot;i++){
            int st=ST[i],ed=ED[i],lca=LCA(st,ed);
            if((deep[st]+deep[ed]-2*deep[lca]+1)%2==0)cnt[st]--,cnt[ed]--,cnt[lca]+=2;
            else cnt[st]++,cnt[ed]++,cnt[lca]-=2,sum++;
        }
        memset(vis,false,sizeof(vis));
        for(int i=1;i<=n;i++){
            if(vis[i])continue;
            mark[i]=true;
            solve(i,0);
        }
        for(int i=1;i<=n;i++){
            if(mark[i])continue;
            if(cnt[i]==sum)ans++;
        }
        if(sum==1)ans++;
        printf("%d",ans);
        return 0;
    }
    
  • 相关阅读:
    望其项背 iOS
    望其项背 iOS
    望其项背 iOS
    望其项背 iOS
    望其项背 iOS
    望其项背 iOS
    望其项背 iOS
    望其项背 iOS
    望其项背 iOS
    望其项背 iOS
  • 原文地址:https://www.cnblogs.com/SillyTieT/p/11476923.html
Copyright © 2011-2022 走看看