• CF19E Fairy


    题目链接

    题意分析

    一个图是二分图的充要条件:该图中不存在奇环

    由于奇偶性的关系 复杂奇环的产生一定源于简单奇环 所以我们仅仅考虑删去一条边使得所有简单奇环被破坏

    也就说 我们仅仅考虑简单环

    首先 我们从这张图中拽出一个生成树

    然后 对于非树边 如果加上去的话 必然会产生一个环 我们需要统计会产生奇环的数量cnt

    如果cnt=0

    那么一开始就不再奇环 而我们删边是不可能删出奇环的 所以这种情况下m条边都可以删

    如果cnt≠0

    树边

    对于每一条树边 如果参与构成奇数环的话 就是a类型边 否则就是b类型边

    显然我们对于树边就是要讨论a类型边中哪些边删了会使得奇环全部消失

    第一反应 很显然 如果一条树边参与形成了全部奇环的话 是必须要删除的

    但是 会存在这么一种情况

    无标题.png

    其中黑色的是树边 显然 我们应该删除紫边 但是紫边不仅参与形成了奇环 还参与形成了偶环 由于奇偶性 删除了紫边 还会有一个大奇环

    所以我们要删除的是参与形成奇环并且没有参与形成偶环的树边

    这个的话 利用树上差分赋值边权的方法可以办到

    对于奇数环上的树边边权+1 对于偶数环上的树边边权-1

    最后边权=cnt的树边就是我们要删除的树边

    非树边

    如果存在多个奇环的话 只删掉一条非树边显然只能消去一个奇环 不可行

    如果只存在一个奇环的话 只删掉一条非树边显然是可行的

    一定要注意的是 题目给出的图可能不是连通图

    CODE:

    #include<bits/stdc++.h>
    using namespace std;
    #define M 10080
    int n,m,tot,cnt;
    int bel[M];
    vector<pair<int,int> > G[M];
    int dep[M],fa[M][20],siz[M],id[M];
    int sum[M],ans[M];
    bool vis[M];
    struct Edge
    {
    	int u,v;
    	bool tag;
    }e[M];
    int find(int x)
    {return x==bel[x] ? x:bel[x]=find(bel[x]);}
    void add(int x,int y,int z)
    {G[x].push_back(make_pair(y,z));}
    void dfs(int now,int fat)
    {
    	dep[now]=dep[fat]+1;fa[now][0]=fat;
    	for(int i=1;(1<<i)<=dep[now];++i)
    	fa[now][i]=fa[fa[now][i-1]][i-1];
    	for(int i=0;i<(int)G[now].size();++i)
    	{
    		int v=G[now][i].first;
    		if(v==fat) continue;
    		id[v]=G[now][i].second;dfs(v,now);
    	}
    }
    int LCA(int nowx,int nowy)
    {
    	if(dep[nowx]<dep[nowy]) swap(nowx,nowy);
    	for(int i=16;i>=0;--i)
    	if(dep[fa[nowx][i]]>=dep[nowy]) nowx=fa[nowx][i];
    	if(nowx==nowy) return nowx;
    	for(int i=16;i>=0;--i)
    	if(fa[nowx][i]!=fa[nowy][i]) 
    	nowx=fa[nowx][i],nowy=fa[nowy][i];
    	return fa[nowx][0];
    }
    void dfs_sum(int now,int fat)
    {
    	vis[now]=1;
    	for(int i=0;i<(int)G[now].size();++i)
    	{
    		int v=G[now][i].first;
    		if(v==fat) continue;
    		dfs_sum(v,now);
    		sum[now]+=sum[v];
    	}
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;++i)
    	{
    		scanf("%d%d",&e[i].u,&e[i].v);
    		e[i].tag=0;
    	} 
    	for(int i=1;i<=n;++i) bel[i]=i;
    	for(int i=1;i<=m;++i)
    	{
    		int fx=find(e[i].u),fy=find(e[i].v);
    		if(fx==fy) continue;
    		bel[fx]=fy;e[i].tag=1;
    		add(e[i].u,e[i].v,i);add(e[i].v,e[i].u,i); 	
    	} 
    	for(int i=1;i<=n;++i) if(!dep[i]) dfs(i,0);
    	tot=0;
    	for(int i=1;i<=m;++i)
    	{
    		if(e[i].tag) continue;
    		int lca=LCA(e[i].u,e[i].v);
    		int tmpnum=dep[e[i].u]+dep[e[i].v]-(dep[lca]<<1);
    		if((tmpnum+1)&1)//是奇环的话
    		{
    			sum[e[i].u]++;sum[e[i].v]++;
    			sum[lca]-=2;
    			++tot;
    		} 
    		else//是偶环的话 
    		{
    			sum[e[i].u]--;sum[e[i].v]--;
    			sum[lca]+=2;
    		}
    	}
    	for(int i=1;i<=n;++i) if(!vis[i]) dfs_sum(i,0);
    	if(tot==0)
    	{
    		printf("%d\n",m);
    		for(int i=1;i<=m;++i) printf("%d%c",i,(i==m ? '\n':' ')); 
    	}
    	if(tot==1)
    	{
    		for(int i=1;i<=m;++i)
    		{
    			if(e[i].tag) continue;
    			int lca=LCA(e[i].u,e[i].v);
    			int tmpnum=dep[e[i].u]+dep[e[i].v]-(dep[lca]<<1);
    			if((tmpnum+1)&1) ans[++cnt]=i;
    		}	
    		for(int i=1;i<=n;++i)
    		if(sum[i]==1) ans[++cnt]=id[i];
    		sort(ans+1,ans+cnt+1);
    		printf("%d\n",cnt);
    		for(int i=1;i<=cnt;++i) printf("%d%c",ans[i],(i==cnt ? '\n':' ')); 
    	}
    	if(tot>1)
    	{
    		
    		for(int i=1;i<=n;++i)
    		if(sum[i]==tot) ans[++cnt]=id[i];
    		sort(ans+1,ans+cnt+1);
    		printf("%d\n",cnt);
    		for(int i=1;i<=cnt;++i) printf("%d%c",ans[i],(i==cnt ? '\n':' ')); 
    	}
    	return 0;
    } 
    
  • 相关阅读:
    火炬之光模型导出(Unity载入火炬之光的模型)
    树的左旋与右旋
    javaEE开发之导出excel工具类
    STL algorithm算法is_permutation(27)
    学做衣服论坛 -服装DIY教程,缤纷服装网,裁剪教程,家用缝纫机,买布料
    傲娇_百度百科
    《失败不是成功之母》阅读理解
    失败是不是成功之母
    正则表达式多语种的web版本
    date tod = boost::gregorian::day_clock::local_day(); //当前日期
  • 原文地址:https://www.cnblogs.com/tcswuzb/p/14366522.html
Copyright © 2020-2023  润新知