【BZOJ】P4238 电压

时间:2019-09-06
本文章向大家介绍【BZOJ】P4238 电压,主要包括【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;
}

原文地址:https://www.cnblogs.com/SillyTieT/p/11476923.html