$bzoj1116-POI2008$ $CLO$ 并查集

  • 题面描述
    • \(Byteotia\)城市有\(n\)\(towns\)\(m\)条双向\(roads\). 每条 \(road\) 连接 两个不同的 \(towns\) ,没有重复的\(road\).
    • 你要把其中一些\(road\)变成单向边使得:每个\(town\)都有且只有一个入度
  • 输入格式
    • 第一行输入\(n,m\). \((1 \leq n\leq 10^5,1\leq m \leq 2*10^5)\)
    • 下面\(M\)行用于描述\(M\)条边.
  • 输出格式
    • \(TAK/NIE\)
  • 题解
    • 考虑每个点都有一个入度,因此 被定向的边数\(=\)点数,因此不难想到被定向后的边组成的图形是一个基环外向树,因此在原图每个联通块中,必然要存在一个环,不然就不能达成目的
    • 因此用并查集判断是否有环即可
      • 具体来说,一条一条边加入,当将要被加入的点已经在要加入的集合中时即存在环
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e5+5;
const int MAXM=1e6+6;
int n,m,fa[MAXN];
int mark[MAXN];
int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); }
void uion(int x,int y){ 
	int fx=find(x),fy=find(y);
	fa[fx]=fy;
	mark[fy]|=mark[fx];
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) fa[i]=i;
	for (int i=1;i<=m;i++){
		int u,v; scanf("%d%d",&u,&v);
		int fu=find(u),fv=find(v);
		if (fu!=fv) uion(u,v);
		else mark[fu]=1;
	}
	for (int i=1;i<=n;i++){
		int fi=find(i);
		if (!mark[fi]) return printf("NIE\n"),0;
	}
	printf("TAK\n");
	return 0;
}

posted @ 2019-05-10 14:12  paul120090105  阅读(116)  评论(0)    收藏  举报