• 题解「AT1226 電圧」


    转载注明来源:https://www.cnblogs.com/syc233/p/13647723.html


    题意

    给定(n) 个点 (m) 条边的无向图,现在要对每个点黑白染色。

    若能够使一条边连接的两点颜色相同,其他边连接的两点颜色不同,则这条边合法。

    求合法的边数。

    (2 leq n leq 10^5,1 leq m leq 2 cdot 10^5)

    图可能不连通,不保证没有重边。


    题解

    删去边后图能够二染色,则这条边合法的必要条件是删边后的图是二分图,即没有奇环。那么合法的边必然在所有奇环上。

    又因为偶环上的点一定是黑白交替出现,所以合法边必然不在偶环上。

    不难想到对这个无向图求 DFS 树,再进行树上差分即可求出每一条树边在几个奇环和偶环中出现。

    对于非树边(返祖边),分类讨论:

    • 若图中只有一个奇环,则这个奇环对应的非树边合法。

    • 若图中有不止一个奇环,再分类讨论:

      • 若有两个奇环相交,则这两个环会构成一个大环,并且这个大环一定是偶环,则两个奇环的返祖边均不合法。
      • 若有两个奇环不相交,则没有边同时处于这两个奇环,返祖边显然也不合法。

    所以求出树边上合法边的总数,再判断奇环是否只有一个即可。


    ( ext{Code}:)

    #include <cstdio>
    #define maxn 100005
    #define maxm 200005
    #define Rint register int
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long lxl;
    
    template <typename T>
    inline void read(T &x)
    {
    	x=0;T f=1;char ch=getchar();
    	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	x*=f;
    }
    
    struct edge
    {
    	int u,v,next;
    	edge(int u,int v,int next):u(u),v(v),next(next){}
    	edge(){}
    }e[maxm<<1];
    
    int head[maxn],k;
    
    inline void add(int u,int v)
    {
    	e[k]=edge(u,v,head[u]);
    	head[u]=k++;
    }
    
    int n,m;
    int dep[maxn];
    bool vis[maxm];
    int odd[maxn],oddcnt;
    int eve[maxn],evecnt;
    
    inline void dfs(int u,int fa)
    {
    	vis[u]=true;
    	for(int i=head[u];~i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if((i^1)==fa) continue;
    		if(!vis[v])
    		{
    			dep[v]=dep[u]+1;
    			dfs(v,i);
    			eve[u]+=eve[v];
    			odd[u]+=odd[v];
    		}
    		else if(dep[v]<dep[u])
    		{
    			if((dep[u]-dep[v])&1)
    				++evecnt,++eve[u],--eve[v];
    			else
    				++oddcnt,++odd[u],--odd[v];
    		}
    	}
    }
    
    int main()
    {
    	// freopen("AT1226.in","r",stdin);
    	read(n),read(m);
    	for(int i=1;i<=n;++i) head[i]=-1;
    	for(int i=1,u,v;i<=m;++i)
    	{
    		read(u),read(v);
    		add(u,v);add(v,u);
    	}
    	for(int i=1;i<=n;++i)
    		if(!vis[i]) dfs(i,-1);
    	int ans=0;
    	for(int i=1;i<=n;++i)
    	{
    		if(!dep[i]) continue;
    		ans+=(!eve[i]&&odd[i]==oddcnt);
    	}
    	ans+=(oddcnt==1);
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    DBHelper类
    户籍不在本市并已申请基本养老保险或基本医疗保险关系转移手续销户提取业务办理指南(试行)
    Android 打开/播放电脑的音频/视频文件
    (技术贴)如何鉴定绿茶婊
    Swift初探(一)
    关于android移动终端IM的一些问题
    C++中对象、引用、指针
    TextView
    新API
    开发者必备的6款源码搜索引擎
  • 原文地址:https://www.cnblogs.com/syc233/p/13647723.html
Copyright © 2020-2023  润新知