#include<bits/stdc++.h>
using namespace std;
const int MAXN = 512;
const int MAXM = 65536;
vector<int> e[MAXN];
int d[MAXN][MAXN];
int xx, yy, zz;
bool dfs(int p, int s, int t) {
if (s == t) {//如果是终点,则返回可以到达
return true;
} else {
for (vector<int>::const_iterator i = e[s].begin(); i != e[s].end(); ++i) {
if (*i != p && dfs(s, *i, t)) {//遍历不是父节点的边,如果是删除边,则记录下来
if (zz > d[s][*i]) {
xx = s;
yy = *i;
zz = d[xx][yy];
}
return true;
}
}
return false;
}
}
char c[MAXM];
int x[MAXM], y[MAXM];
int main() {
int ri = 0;
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = 0; i < n; ++i) {
e[i].clear();
fill(d[i], d[i] + n, MAXM);
}
for (int i = 0; i < m; ++i) {
scanf(" %c%d%d", &c[i], &x[i], &y[i]);
--x[i];
--y[i];
if (c[i] == 'D') {
d[x[i]][y[i]] = d[y[i]][x[i]] = i;//加可以删除边的标志
}
}
if (ri > 0) {
puts("");
}
printf("Case %d:\n", ++ri);
for (int i = 0; i < m; ++i) {
if (c[i] == 'I') {
zz = MAXM;//每次都是没找到要删除的节点
if (dfs(-1, x[i], y[i])) {
if (zz < d[x[i]][y[i]]) {//如果已经连接,里面并有一条可以删除的边,则可以把它删除
e[xx].erase(remove(e[xx].begin(), e[xx].end(), yy), e[xx].end());
e[yy].erase(remove(e[yy].begin(), e[yy].end(), xx), e[yy].end());
e[x[i]].push_back(y[i]);
e[y[i]].push_back(x[i]);
}
//如果没有则可以不加,那么保证图是一颗树,访问一次的时间则是O(n)
} else {
e[x[i]].push_back(y[i]);
e[y[i]].push_back(x[i]);
}
} else if (c[i] == 'D') {//删除则直接删
e[x[i]].erase(remove(e[x[i]].begin(), e[x[i]].end(), y[i]), e[x[i]].end());
e[y[i]].erase(remove(e[y[i]].begin(), e[y[i]].end(), x[i]), e[y[i]].end());
} else {
if(dfs(-1,x[i],y[i]))printf("YES\n");
else printf("NO\n");
}
}
}
return 0;
}
思路就是一直保证图是一颗树,可以提前删除的边就提前删除,保证每一个操作都是O(n),这样就不会超时,判断可不可以满足,用dfs来搜索,如果有则把它记录下来,在插入时直接删除