Loading

题解-CF1239D Catowice City

CF1239D Catowice City

\(n\) 个人和 \(n\) 只猫。有 \(m\) 对人猫友谊,即第 \(u_i\) 个人认识第 \(v_i\) 只猫,保证第 \(i\) 个人和第 \(i\) 只猫认识。求 \(j\) 个人和 \(p\) 只猫使 \(j+p=n(1\le j,p<n)\),并且这些人和猫互不认识。\(t\) 组测试数据。

数据范围: \(1\le n\le m\le 10^6\)\(1\le \sum n,\sum m\le 10^6\)


首先这是个二分图,人一块,猫一块。

将第 \(i\) 个人和第 \(i\) 只猫合并成一点,因为他们不能都选。

\(u_i\)\(v_i\) 连一条有向边,表示如果第 \(u_i\) 点选人,\(v_i\) 点也必须选人

如果出现环,则这些点要么全选人要么全选猫,不妨令选人。

所以 \(\texttt{Tarjan}\)强联通分量分出来。

如果只有一个强联通分量,则必须全选人,与 \((1\le j,p<n)\) 不符,输出 \(\texttt{No}\)

否则选出拓扑序最后的强联通分量全选人,其他全选猫

\(\texttt{Tarjan}\) 有个性质:编号为 \(1\) 的强联通分量拓扑序最后。

时间复杂度 \(\Theta(n+m)\),空间复杂度 \(\Theta(n+m)\)


  • 代码:
#include <bits/stdc++.h>
using namespace std;

//Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x(a) a.first
#define y(a) a.second
#define b(a) a.begin()
#define e(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;

//Data
const int N=1e6;
int n,m;
vector<int> e[N+7];

//Tarjan
int ic,in[N+7],low[N+7],dfn[N+7],sc,st[N+7],cc,co[N+7],sm[N+7];
void Tarjan(int u){
	low[u]=dfn[u]=++ic,in[u]=1,st[++sc]=u;
	for(int v:e[u])
		if(!dfn[v]) Tarjan(v),low[u]=min(low[u],low[v]);
		else if(in[v]) low[u]=min(low[u],dfn[v]);
	if(dfn[u]==low[u]) for(int v=0,t=++cc;v!=u;) v=st[sc--],co[v]=t,in[v]=0,sm[t]++;
}

//KonnyWen
void KonnyWen(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) e[i].clear();
	for(int i=1;i<=m;i++){
		int u,v; scanf("%d%d",&u,&v);
		if(u!=v) e[u].pb(v);
	}
	fill(dfn+1,dfn+n+1,0),fill(sm+1,sm+n+1,0),ic=sc=cc=0;
	for(int i=1;i<=n;i++)if(!dfn[i]) Tarjan(i);
	if(cc==1) return void(puts("No"));
	printf("Yes\n%d %d\n",sm[1],n-sm[1]);
	for(int i=1;i<=n;i++)if(co[i]==1) printf("%d ",i); puts("");
	for(int i=1;i<=n;i++)if(co[i]!=1) printf("%d ",i); puts("");
}

//Main
int main(){
	int t; scanf("%d",&t);
	for(int ti=1;ti<=t;ti++) KonnyWen();
	return 0;
}

祝大家学习愉快!

posted @ 2020-05-19 14:40  George1123  阅读(116)  评论(0编辑  收藏  举报