【POJ 1703】 Find them, Catch them(关系并查集)
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 38951 | Accepted: 11987 |
Description
Input
Output
Sample Input
1 5 5 A 1 2 D 1 2 A 1 2 D 2 4 A 1 4
Sample Output
Not sure yet. In different gangs. In the same gang.
Source
关系并查集入门题目,如果做过食物链应该这个就小case了,。
题目大意是有两个犯罪团伙,给出总人数n,之后m个操作
D a b表示已知a和b不是一个团伙
A a b表示询问a与b的关系
这样可以建立一个并查集,另外开一个数组表示当前目标与它父亲的关系 1表示不在同一团伙 0表示在同一团伙。
可以试试倒过来表示 会发现后面处理起来稍微麻烦点
这样表示的话 对于预处理 所有的pre[x] = x rex[x] = 0(每个点单独是一个集合 与自己关系为0(处在同集合))
对于操作D a b找到a与b所在集合的根k r 如果k == r直接return 否则合并两集合 由于a和b不在同一集合 同时rex[a] rex[b]已知 由此可推出合并后k和r的关系
最后可以得到公式 rex[k] = rex[a]^rex[b]^1
这个。。。怎么得到的话稍微枚举下然后检测下正确性。。。弱只会这种方法推……
对于查询就好说了 如果两集合根不想等 就说明还没建立关系 返回那句话
否则说明a和b在同一集合 然后根据rex[a] rex[b] 很容易推出a和b的关系 做成公式就是rex[a]^rex[b]
代码如下:
#include <iostream> #include <cmath> #include <vector> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <stack> #include <list> #include <algorithm> #include <map> #include <set> #define LL long long #define Pr pair<int,int> #define fread() freopen("in.in","r",stdin) #define fwrite() freopen("out.out","w",stdout) using namespace std; const int INF = 0x3f3f3f3f; const int msz = 10000; const int mod = 1e9+7; const double eps = 1e-8; int pre[233333]; bool rex[233333]; void init(int n) { for(int i = 1; i <= n; ++i) { pre[i] = i; rex[i] = 0; } } int Find(int x) { int k = pre[x]; if(pre[x] != x) { pre[x] = Find(pre[x]); rex[x] ^= rex[k]; k = pre[x]; } return k; } void Union(int u,int v) { int k = Find(u); int r = Find(v); if(k == r) return; pre[k] = r; rex[k] = rex[u]^rex[v]^1; } void Search(int u,int v) { int k = Find(u); int r = Find(v); if(k != r) { puts("Not sure yet."); return; } puts((rex[u]^rex[v])? "In different gangs.": "In the same gang."); } int main() { //fread(); //fwrite(); int t,n,m,u,v; char opt[2]; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); init(n); while(m--) { scanf("%s%d%d",opt,&u,&v); if(opt[0] == 'D') { Union(u,v); }else Search(u,v); } } return 0; }