"蔚来杯"2022牛客暑期多校训练营3 F-Fief补题

合法的几种情况:
1、只有两个点
2、缩完点后只有一个点双连通分量
3、缩完点后是一条链,两个点不是割点并且分别位于链的两端

wa了好几发的原因:判断缩完点之后是否为一条链,既要满足每个连通分量内的割点数量<3,也要满足每个割点所处连通分量的个数<3(可以手动模拟一下,发现对应两种不同的情况)
#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 1e5 + 10, M = 4e5 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int n, m;
int st[N], st_cnt;
int cut_cnt[N];

int head[N], idx;

struct EGDE {
	int to, next;
} eg[M];

void add(int x, int y) {
	eg[idx].to = y;
	eg[idx].next = head[x];
	head[x] = idx++;
}

int dfn[N], low[N], timestamp;
int stk[N], top;
int dcc_cnt;
vector<int> dcc[N];
bool cut[N];

void tarjan(int u, int root) {
	dfn[u] = low[u] = ++ timestamp;
	stk[ ++ top] = u;

	if (u == root && head[u] == -1) {
		dcc_cnt ++ ;
		dcc[dcc_cnt].push_back(u);
		return;
	}

	int cnt = 0;
	for (int i = head[u]; ~i; i = eg[i].next) {
		int j = eg[i].to;
		if (!dfn[j]) {
			tarjan(j, root);
			low[u] = min(low[u], low[j]);
			if (dfn[u] <= low[j]) {
				cnt ++ ;
				if (u != root || cnt > 1) cut[u] = true;
				++ dcc_cnt;
				int y;
				do {
					y = stk[top -- ];
					dcc[dcc_cnt].push_back(y);
				} while (y != j);
				dcc[dcc_cnt].push_back(u);
			}
		} else low[u] = min(low[u], dfn[j]);
	}
}

void work() {
	memset(head, -1, sizeof head);
	cin >> n >> m;
	rep(i, 1, m) {
		int x, y;
		cin >> x >> y;
		add(x, y);
		add(y, x);
	}
	int q;
	cin >> q;

	if (n == 2) {
		while (q--) cout << "YES" << endl;
		return;
	}

	int k = 0;
	rep(i, 1, n)
	if (!dfn[i]) k++, tarjan(i, i);

	if (k > 1) {
		while (q--) cout << "NO" << endl;
		return;
	}

	rep(i, 1, dcc_cnt) {
		k = 0;
		rep(j, 0, dcc[i].size() - 1)
		if (cut[dcc[i][j]]) k++, cut_cnt[dcc[i][j]]++;
		if (k >= 3) {
			while (q--) cout << "NO" << endl;
			return;
		} else if (k == 1) {
			st_cnt++;
			rep(j, 0, dcc[i].size() - 1)
			if (!cut[dcc[i][j]]) st[dcc[i][j]] = st_cnt;
		}
	}
	rep(i, 1, n)
	if (cut[i] && cut_cnt[i] >= 3) {
		while (q--) cout << "NO" << endl;
		return;
	}

	//到这里肯定是一条链
	while (q--) {
		int x, y;
		cin >> x >> y;
		if (dcc_cnt == 1) cout << "YES" << endl;
		else if (st[x] && st[y] && st[x] != st[y]) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
}

signed main() {
	IO
	int test = 1;
	// 	cin >> test;

	while (test--) {
		work();
	}

	return 0;
}
posted @ 2022-07-30 02:14  xhy666  阅读(50)  评论(0)    收藏  举报