您的位置:首页 > 其它

POj 1703 Find them, Catch them(关系并查集)

2015-06-02 21:49 302 查看
题目: 戳我

题意:城市中有两个社会团伙

已知有n个人:编号为1~n,和m个信息

对于每个信息,D a b表明a和b属于不同的团伙,并且信息不会相互矛盾;A a b表示讯问a和b的关系,

要求依次回答每个讯问,回答形式如下:

Not sure yet. //a和b的关系不确定

In different gans. //a和b属于不同的团伙

In the same gang. //a和b属于同一个团伙

回顾并查集的合并操作:我们总是将同类的集合进行合并,但此题给出的却是不同类的两个元素。

抓住关键,城市的团伙只有两个,这个信息告诉我们:如果a和b不同类,b和c不同类,那么a和c必然属于一个团伙。

更一般的,如果我们把编号看做顶点,关系看做连边。那么,如果顶点a,b之间的路径包含奇数条边,那么a与b属于不同的团伙,如果a,b之间的路径包含偶数条边,那么a与b属于同一个团伙。

我们能够很容易的计算出元素x与根节点的“距离”(即路径上经过的边数)dis[x]。类似的,对于与x同属一个集合的任意元素y,我们也可以计算出y与根节点的“距离”dis[y]。那么,x与y的“距离”便可以用dis[x]+dis[y]表示。(注意,我们只关心“距离”的奇偶性,并不关心“距离”是否是最短的)

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>

using namespace std;

const int inf = 0x3f;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+5;

int bleg[maxn], dis[maxn], n, q;

int find(int x)
{
int y = x, cnt = 0;
while(y != bleg[y])
{
cnt += dis[y];
y = bleg[y];
}
while(x != bleg[x])
{
int px = bleg[x], tmp = dis[x];
dis[x] = cnt;
bleg[x] = y;
cnt -= tmp;
x = px;
}
return y;
}

void Union(int a, int b)
{
int pa = find(a), pb = find(b);
if(pa == pb) return;
dis[pa] = dis[a] + dis[b] + 1;
bleg[pa] = pb;
}

void Init()
{
for(int i = 0; i <= n; i++)
{
bleg[i] = i; dis[i] = 0;
}
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &q);
Init();
while(q--)
{
int x, y;
char op;
scanf(" %c %d %d", &op, &x, &y);
if(op == 'A')
{
int pa = find(x), pb = find(y);
if(pa != pb)
{
puts("Not sure yet.");
}
else if((dis[x] + dis[y]) % 2 != 0)
{
puts("In different gangs.");
//printf("%d %d\n", dis[x], dis[y]);
}
else
{
puts("In the same gang.");
}
}
else
{
Union(x, y);
}
}
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: