BZOJ 1116: [POI2008]CLO 并查集

来源:互联网 发布:mac os 彻底删除软件 编辑:程序博客网 时间:2024/06/14 09:14

Description

Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 你要把其中一些road变成单向边使得:每个town都有且只有一个入度
Input

第一行输入n m.1 <= n<= 100000,1 <= m <= 200000 下面M行用于描述M条边.
Output

TAK或者NIE 常做POI的同学,应该知道这两个单词的了…
Sample Input
4 5

1 2

2 3

1 3

3 4

1 4

解题方法: 这题和scoi的游戏差不多,首先我们先判断什么情况下不存在?首先这图不一定连通,所以我们要分连通块来考虑,对于一个连通块来说,如果这个连通块是一颗树的话,那么这种情况肯定GG的,那么还有其他不存在的情况吗?想想发现没有了。所以我们关键就是要维护每个连通块看是否是有环?所以我们就可以用并查集来维护了。给每个连通块的根一个标记。合并俩个连通块时只要任意一个连通块带有标记新的连通块就带有标记。如果一条边的俩个点已经在同一个连通块内了,直接将根打上标记即可。

#include <bits/stdc++.h>using namespace std;const int maxn = 100010;int n, m, fa[maxn];bool mark[maxn];int find_set(int x){    if(x == fa[x]) return x;    else return fa[x] = find_set(fa[x]);}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 x = find_set(u), y = find_set(v);        if(x == y){            mark[x] = 1;        }        else{            fa[x] = y;            mark[y] = (mark[x] | mark[y]);        }    }    for(int i = 1; i <= n; i++){        int rt = find_set(i);        if(!mark[rt]){            printf("NIE\n");            return 0;        }    }    printf("TAK\n");    return 0;}
0 0