D. Edge Split

Problem - D - Codeforces

思路:思路想到了,但是不知道用什么方法写。。首先我们先看只有一个树的情况,那么如果我们所有的边是一个颜色,那么答案是1+n,如果我们将其中的一条边变色,那么产生的答案是2+n-1,答案是不变的,如果有n条边,同样的方式我们如果所有的边为一个颜色,那么产生答案是1+n,但是n条边的树是存在环的,我们可以将环上的一条边变为另一个颜色那么答案就会变成1+n-1,所以我们通过总结发现,只要同一种颜色没有环,最终的答案就是最小的。那么现在问题就变成了构造两个无环图,我们可以先构造一颗树,那么最多会剩下3条边,如果剩下的三条边能够构成环,那么我们任意的选择一条边,加到树上,然后选择这条边的某个顶点,然后把这个顶点在树种的所有连边全都删除,除了新加的这条边,这样是一定不会有环的,因为首先树上是肯定没有环的,可能剩下的边存在环,因为新砍下来边是从树上看下来的,那么它们之间肯定是不能够形成环的,并且这写边与剩下的两个一定也不能够构成,因为没有重边的存在,要构成环那么只能是之前新加的那条边,所以肯定也不可能

// Problem: D. Edge Split
// Contest: Codeforces - Codeforces Round 819 (Div. 1 + Div. 2) and Grimoire of Code Annual Contest 2022
// URL: https://codeforces.com/contest/1726/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms

#include<bits/stdc++.h>
#include<sstream>
#include<cassert>
#define fi first
#define se second
#define i128 __int128
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
const double eps=1e-7;
const int N=5e5+7 ,M=5e5+7, INF=0x3f3f3f3f,mod=1e9+7,mod1=998244353;
const long long int llINF=0x3f3f3f3f3f3f3f3f;
inline ll read() {ll x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=(ll)x*10+c-'0';c=getchar();} return x*f;}
inline void write(ll x) {if(x < 0) {putchar('-'); x = -x;}if(x >= 10) write(x / 10);putchar(x % 10 + '0');}
inline void write(ll x,char ch) {write(x);putchar(ch);}
void stin() {freopen("in_put.txt","r",stdin);freopen("my_out_put.txt","w",stdout);}
bool cmp0(int a,int b) {return a>b;}
template<typename T> T gcd(T a,T b) {return b==0?a:gcd(b,a%b);}
template<typename T> T lcm(T a,T b) {return a*b/gcd(a,b);}
void hack() {printf("\n----------------------------------\n");}

int T,hackT;
int n,m,k;
int ans[N];
PII edge[N];
int f[N];
int h[N],e[M],ne[M],idx;
bool st[N];

void add(int a,int b) {
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

int find(int x) {
	if(x!=f[x]) f[x]=find(f[x]);
	return f[x];
}

int dfs(int u,int fa,bool &flag) {
	if(st[u]) {
		flag=true;
		return 0;
	}
	st[u]=true;
	int res=1;
	for(int i=h[u];i!=-1;i=ne[i]) {
		int j=e[i];
		
		if(j==fa) continue;
		res+=dfs(j,u,flag);
	}
	
	return res;
}

bool check(vector<PII> &vis) {
	for(int i=0;i<=n;i++) h[i]=-1,st[i]=false;
	idx=0;
	
	for(int i=0;i<vis.size();i++) {
		int a=vis[i].fi,b=vis[i].se;
		add(a,b),add(b,a);
	}
	
	bool flag=false;
	if(dfs(vis[0].fi,-1,flag)==3&&flag) return true;
	else return false;
}

void solve() {
	n=read(),m=read();
	
	for(int i=1;i<=n;i++) f[i]=i;
	for(int i=1;i<=m;i++) ans[i]=0;
	
	vector<PII> vis;
	for(int i=1;i<=m;i++) {
		int a=read(),b=read();
		edge[i]={a,b};
		int fa=find(a),fb=find(b);
		
		if(fa!=fb) {
			f[fa]=fb;
			ans[i]=1;
		}else vis.push_back({a,b});
	}
	
	if(vis.size()==3) {
		if(check(vis)) {
			int id=vis[0].fi;
			for(int i=1;i<=m;i++) {
				if(!ans[i]) continue;
				if(edge[i].fi==id||edge[i].se==id) ans[i]=0;
			}
			for(int i=1;i<=m;i++) {
				if(edge[i].fi==vis[0].fi&&edge[i].se==vis[0].se) ans[i]=1;
			}
		}
	}
	
	for(int i=1;i<=m;i++) printf("%d",ans[i]);
	printf("\n");
}   

int main() {
    // init();
    // stin();
	// ios::sync_with_stdio(false); 

    scanf("%d",&T);
    // T=1; 
    while(T--) hackT++,solve();
    
    return 0;       
}          

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值