gym 101741 E Code-Cola Plants 题解

89 篇文章 1 订阅

首先可以发现由于图是无环的,所以原问题 ⇔ \Leftrightarrow 2 ∗ ( n − 1 ) 2*(n-1) 2(n1)条边其中满足这个边集的诱导子图除了 a a a的每一个点都有 1 1 1的入度,每一个除了 b b b的点有 1 1 1的出度。

然后就可以很轻松转换成网络流的题。时间复杂度 O ( n + m ∗ n ) O(n+m*\sqrt n) O(n+mn )会TLE。

但是由于一个边只配两个点,所以可以构造基环数。时间复杂度 O ( n + m ) O(n+m) O(n+m)

Code:

/*
{By GWj
*/
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define R(a) cin>>a
#define R2(a,b) cin>>a>>b
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
vector<int> g[1000000+1],id[1000000+1];
int n,m,a,b;
int siz[1000000+1];
bool spe[1000000+1];
struct DSU{
	int fa[1000000+1],inc[1000000+1];
	void init(int N){
		rb(i,1,N)
			fa[i]=i,inc[i]=1;
	}
	int root(int N){
		if(fa[N]==N) return N;
		return fa[N]=root(fa[N]);
	}
	void merge(int u,int v){
		inc[root(v)]+=inc[root(u)];
		fa[root(u)]=root(v);
	}
}dsu;
int rest[1000000+1];
bool vis[1000000+1];
void work1(int root){
	vis[root]=1;
	rep(i,g[root].size()){
		int it=g[root][i];
		if(!vis[it]){
			if(it>n/2)
			rest[id[root][i]]=1;
			else 
			rest[id[root][i]]=2;
			work1(it);
		}
	}
}
int zz=0;
bool find_cycle;
bool work(int root,int pre){
	vis[root]=1;
	bool okk=0;
	rep(i,g[root].size()){
		int it=g[root][i];
		if(it==pre){
			pre=-1;
			continue;
		}
		if(vis[it]){
			if(find_cycle) continue;
			find_cycle=1;
			zz=it;
			rest[id[root][i]]=(zz>n/2? 1:2);
		}
		else{
			if(work(it,root)) {
				okk=1;
				rest[id[root][i]]=(root>n/2? 1:2);	
			}
			else{
				rest[id[root][i]]=(it>n/2? 1:2);
			}
		}
	}
	if(root==zz) okk=1;
	return  okk;
}
void mian(){
	n<<=1;
	rb(i,1,n)
		g[i].clear(),id[i].clear();
	dsu.init(n);
	rb(i,1,n)
		siz[i]=0,vis[i]=0;
	vector<mp> edges;
	rb(i,1,m){
		rest[i]=0;
		int u,v;
		R2(u,v);
		edges.PB(II(u,v));
		dsu.merge(u,v+n/2);
		id[u].PB(i);
		id[v+n/2].PB(i);
		g[u].PB(v+n/2);
		g[v+n/2].PB(u);
	}
	for(mp edg:edges){
		siz[dsu.root(edg.FIR)]++;
	}
	spe[dsu.root(a+n/2)]=1;
	spe[dsu.root(b)]=1;
	bool ok=1;
	rb(i,1,n){
		if(dsu.root(i)==i){
			if(!spe[i]&&dsu.inc[i]==siz[i]+1){
				ok=0;
			}
		}
	}
	cout<<(ok? "YES":"NO")<<endl;
	if(ok){
		work1(dsu.root(a+n/2));
		if(dsu.root(a+n/2)!=dsu.root(b)){
			work1(dsu.root(b));
		}
		rb(i,1,n)
		if(!spe[i]&&dsu.root(i)==i)
		zz=0,find_cycle=0,work(i,0);
		vector<int> res1,res2;
		rb(i,1,m)
			if(rest[i])
			if(rest[i]==1) res1.PB(i);
			else res2.PB(i); 
		for(auto it:res1) cout<<it<<" ";cout<<endl;
		for(auto it:res2) cout<<it<<" ";cout<<endl;
	}
	spe[dsu.root(a+n/2)]=0;
	spe[dsu.root(b)]=0;
}
int main(){
	fastio;
	while(cin>>n>>m>>a>>b){
		mian();
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值