ZOJ3509

#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来搜索,如果有则把它记录下来,在插入时直接删除

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值