南邮OJ 1044 连通 OR 不连通

来源:互联网 发布:51单片机仿真器 编辑:程序博客网 时间:2024/05/17 09:28

链接:http://202.119.236.66:9080/acmhome/problemdetail.do?&method=showdetail&id=1044

题目:

连通 OR 不连通

时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte
总提交:250            测试通过:48

描述

给定一个无向图,一共n个点,请编写一个程序实现两种操作:

D x y 从原图中删除连接x,y节点的边。

Q x y 询问x,y节点是否连通

输入

第一行两个数n,m(5<=n<=40000,1<=m<=100000)

接下来m行,每行一对整数 x y (x,y<=n),表示x,y之间有边相连。保证没有重复的边。

接下来一行一个整数 q(q<=100000)

以下q行每行一种操作,保证不会有非法删除。

输出

按询问次序输出所有Q操作的回答,连通的回答C,不连通的回答D

样例输入

3 3
1 2
1 3
2 3
5
Q 1 2
D 1 2
Q 1 2
D 3 2
Q 1 2

样例输出

C
C
D

解题思路:

这道题需要用并查集来做,但是如果单纯地只是使用并查集,在删边时出比较麻烦。对于这个问题,我们可以这么想,先用邻接表存下这张图,然后,将操作序列存下来,将序列中需要删除的边在邻接表中删除,删除之后,将剩余的边加到并查集当中。将刚刚存下来的操作序列,从后往前扫一遍,遇到'Q',判断两个数时候在同一个并查集中,记录下结果,遇到’D‘,则将这条边加入并查集中。最后将结果逆序输入即可。

代码:

#include <iostream>#include <vector>#include <cstring>#include <cstdio>using namespace std;const int MAXN = 100005;const int MAXM = 100005;vector<int> v[MAXN];int n, m, t, set[MAXN], a[MAXM], b[MAXM];char c[MAXM], ans[MAXM];int find(int p){if(set[p] < 0) return p;return set[p] = find(set[p]);}void join(int p, int q){p = find(p);q = find(q);if(p != q) set[p] = q;}int main(){memset(set, -1, sizeof(set));scanf("%d%d", &n, &m);while(m--){int x, y;scanf("%d%d", &x, &y);v[x].push_back(y);v[y].push_back(x);}scanf("%d", &t);for(int i = 0; i < t; i++){getchar();scanf("%c%d%d", &c[i], &a[i], &b[i]);if('D' == c[i]){for(vector<int>::iterator it = v[a[i]].begin(); it < v[a[i]].end(); it++){if(*it == b[i]){v[a[i]].erase(it);break;}}for(vector<int>::iterator it = v[b[i]].begin(); it < v[b[i]].end(); it++){if(*it == a[i]){v[b[i]].erase(it);break;}}}}for(int i = 1; i <= n; i++){for(vector<int>::iterator it = v[i].begin(); it < v[i].end(); it++){join(i, *it);}}int num = 0;for(int i = t - 1; i >= 0; i--){if('Q' == c[i]){int x = find(a[i]);int y = find(b[i]);ans[num++] = (x == y ? 'C' : 'D');}else{join(a[i], b[i]);}}for(int i = num - 1; i >= 0; i--){printf("%c\n", ans[i]);}return 0;}


0 0
原创粉丝点击