题目描述
给定一个无向图,一共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
样例输出
CD
关键在于直接删除边比较麻烦,所以提前读后面的操作,看看有哪些边剩下来,把那些边先组合,最后从后往前一旦遇到操作是删除边的就把边加上去,这样就将删除边转化成并查集的添加边.还有一个关键是判断那些边剩下,用a*MAX+b即可,这样可以直接通过判断book[a*MAX+b]是不是为真,得知a,b是否还存留(而不是被删掉).
之前没有用map,不知道怎么处理,后来看了明神的,所以直接上他的代码了.
#include <cstdio> #include <cstring> #include <map> #include <algorithm> using namespace std; int const MAX = 100005; int n, m, fa[MAX]; char ans[MAX]; struct EDGE { int u, v; bool d; }e[MAX], q[MAX]; map<int, bool> hash; void UF_set() { for(int i = 0; i <= MAX; i++) fa[i] = i; } int Find(int x) { return x == fa[x] ? x : fa[x] = Find(fa[x]); } void Union(int a, int b) { int r1 = Find(a); int r2 = Find(b); if(r1 != r2) fa[r2] = r1; } int main() { UF_set(); scanf("%d %d", &n, &m); for(int i = 0; i < m; i++) { scanf("%d %d", &e[i].u, &e[i].v); if(e[i].u > e[i].v) swap(e[i].u, e[i].v); } int qnum; char s[2]; scanf("%d", &qnum); for(int i = 0; i < qnum; i++) { scanf("%s %d %d", s, &q[i].u, &q[i].v); if(q[i].u > q[i].v) swap(q[i].u, q[i].v); if(s[0] == 'D') { q[i].d = true; hash[q[i].u * MAX + q[i].v] = true; } else q[i].d = false; } for(int i = 0; i < m; i++) if(!hash[e[i].u * MAX + e[i].v]) Union(e[i].u, e[i].v); int cnt = 0; for(int i = qnum - 1; i >= 0; i--) { if(q[i].d) Union(q[i].u, q[i].v); else { if(Find(q[i].u) == Find(q[i].v)) ans[cnt++] = 'C'; else ans[cnt++] = 'D'; } } for(int i = cnt - 1; i >= 0; i--) printf("%c\n", ans[i]); }