【LOJ3077】「2019 集训队互测 Day 4」绝目编诗

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89787306

【题目链接】

【思路要点】

  • 不难发现各个边双连通分量可以分开处理,桥边可以直接删除。
  • 可以证明,对于每一个边双连通分量,当 M N M-N 超过 O ( N ) O(\sqrt{N}) 级别,答案一定为 Y e s Yes
  • 那么,将剩余图中的度为 2 2 的点缩去,剩余的图是一张点数和边数均在 O ( N ) O(\sqrt{N}) 级别的图。
  • 选择一个起始点,找到包含其的所有环,再删去该起始点,每个环会被搜到恰好 2 2 次。
  • 每走出一步均判断当前点与起始点的连通性以确保能够搜到一个环。
  • 至多会搜到 O ( N ) O(N) 个环,每个环环长为 O ( N ) O(\sqrt{N}) 个点,判断连通性需要 O ( N ) O(\sqrt{N}) 的时间。
  • 总时间复杂度 O ( N 2 ) O(N^2)
  • 互测当时笔者采用没有判断连通性的做法配合贪心和卡时输出 N o No 通过了本题。

【代码】

// Standard Solution O(N ^ 2)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int MAXM = 1e6 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int x[MAXM], y[MAXM], f[MAXN];
int n, m, em, v, e, ans[MAXN];
vector <int> a[MAXN], p; set <int> b[MAXN];
vector <pair <pair <int, int>, int>> c[MAXN];
bool vis[MAXN], vise[MAXN], iskey[MAXN];

bool instack[MAXN];
int tot, belong[MAXN], top, Stack[MAXN];
int timer, dfn[MAXN], low[MAXN];
void tarjan(int pos, int fa) {
	low[pos] = dfn[pos] = ++timer;
	v++, e += a[pos].size();
	Stack[++top] = pos;
	instack[pos] = true;
	for (unsigned i = 0; i < a[pos].size(); i++) {
		if (a[pos][i] == fa) continue;
		if (dfn[a[pos][i]] == 0) {
			tarjan(a[pos][i], pos);
			low[pos] = min(low[pos], low[a[pos][i]]);
		} else if (instack[a[pos][i]]) low[pos] = min(low[pos], dfn[a[pos][i]]);
	}
	if (low[pos] == dfn[pos]) {
		int tmp = Stack[top--];
		belong[tmp] = ++tot;
		instack[tmp] = false;
		while (tmp != pos) {
			tmp = Stack[top--];
			belong[tmp] = tot;
			instack[tmp] = false;
		}
	}
}
void rebuild(int from, int fa, int pos, int len) {
	b[fa].erase(pos), b[pos].erase(fa);
	if (iskey[pos]) {
		if (from == pos) {
			ans[len] += 2;
			if (ans[len] >= 3) {
				puts("Yes");
				exit(0);
			}
			return;
		}
		c[from].emplace_back(make_pair(pos, len), ++em);
		c[pos].emplace_back(make_pair(from, len), em);
		return;
	}
	int dest = *b[pos].begin();
	rebuild(from, pos, dest, len + 1);
}
void dfs(int pos) {
	vis[pos] = true;
	v++, e += b[pos].size();
	for (auto x : b[pos])
		if (!vis[x]) dfs(x);
}
int F(int x) {
	if (f[x] == x) return x;
	else return f[x] = F(f[x]);
}
bool connected(int a, int b) {
	for (auto x : p)
		f[x] = x;
	for (auto x : p)
	for (auto y : c[x])
		if (!vise[y.second]) f[F(x)] = F(y.first.first);
	return F(a) == F(b);
}
void work(int pos, int from, int depth) {
	if (!connected(pos, from)) return;
	if (depth && pos == from) {
		if (++ans[depth] >= 3) {
			puts("Yes");
			exit(0);
		}
		return;
	}
	while (!c[pos].empty() && c[pos].back().first.first < from) c[pos].pop_back();
	for (unsigned i = 0; i < c[pos].size(); i++) {
		pair <pair <int, int>, int> x = c[pos][i];
		if (!vise[x.second] && !vis[x.first.first]) {
			vise[x.second] = vis[x.first.first] = true;
			work(x.first.first, from, depth + x.first.second);
			vise[x.second] = vis[x.first.first] = false;
		}
	}
}
int main() {
	read(n), read(m);
	for (int i = 1; i <= m; i++) {
		read(x[i]), read(y[i]);
		a[x[i]].push_back(y[i]);
		a[y[i]].push_back(x[i]);
	}
	for (int i = 1; i <= n; i++) {
		if (dfn[i] == 0) {
			v = 0, e = 0;
			tarjan(i, 0);
			if (e / 2 >= v + sqrt(v) + 2) {
				puts("Yes");
				return 0;
			}
		}
	}
	for (int i = 1; i <= m; i++)
		if (belong[x[i]] == belong[y[i]]) {
			b[x[i]].insert(y[i]);
			b[y[i]].insert(x[i]);
		}
	for (int i = 1; i <= n; i++) {
		iskey[i] = b[i].size() >= 3;
		if (!vis[i]) {
			v = 0, e = 0, dfs(i);
			if (e == 2 * v) {
				ans[v] += 2;
				if (ans[v] >= 3) {
					puts("Yes");
					return 0;
				}
			}
		}
	}
	for (int i = 1; i <= n; i++)
		if (iskey[i]) {
			p.push_back(i);
			while (!b[i].empty()) {
				int dest = *b[i].begin();
				rebuild(i, i, dest, 1);
			}
		}
	for (int i = 1; i <= n; i++) {
		sort(c[i].begin(), c[i].end());
		reverse(c[i].begin(), c[i].end());
	}
	memset(vis, false, sizeof(vis));
	for (int i = 1; i <= n; i++)
		if (iskey[i]) work(i, i, 0);
	puts("No");
	return 0;
}
// Cheating Solution O(Exp(N))
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
const int MAXM = 1e6 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, m, em, v, e, start, ans[MAXN];
int x[MAXM], y[MAXM], p[MAXN], rk[MAXN], rd[MAXN];
vector <int> a[MAXN]; set <int> b[MAXN];
vector <pair <pair <int, int>, int>> c[MAXN];
bool vis[MAXN], vise[MAXN], iskey[MAXN];

bool instack[MAXN];
int tot, belong[MAXN], top, Stack[MAXN];
int timer, dfn[MAXN], low[MAXN];
bool cmp(int x, int y) {
	if (c[x].size() == c[y].size()) return rd[x] < rd[y];
	else return c[x].size() > c[y].size();
}
bool cnp(pair <pair <int, int>, int> x, pair <pair <int, int>, int> y) {
	if (x.first.first == y.first.first) {
		if (x.second == y.second) return x.first.second < y.first.second;
		else return x.second < y.second;
	} else return rk[x.first.first] < rk[y.first.first];
}
void tarjan(int pos, int fa) {
	low[pos] = dfn[pos] = ++timer;
	v++, e += a[pos].size();
	Stack[++top] = pos;
	instack[pos] = true;
	for (unsigned i = 0; i < a[pos].size(); i++) {
		if (a[pos][i] == fa) continue;
		if (dfn[a[pos][i]] == 0) {
			tarjan(a[pos][i], pos);
			low[pos] = min(low[pos], low[a[pos][i]]);
		} else if (instack[a[pos][i]]) low[pos] = min(low[pos], dfn[a[pos][i]]);
	}
	if (low[pos] == dfn[pos]) {
		int tmp = Stack[top--];
		belong[tmp] = ++tot;
		instack[tmp] = false;
		while (tmp != pos) {
			tmp = Stack[top--];
			belong[tmp] = tot;
			instack[tmp] = false;
		}
	}
}
void rebuild(int from, int fa, int pos, int len) {
	b[fa].erase(pos), b[pos].erase(fa);
	if (iskey[pos]) {
		if (from == pos) {
			ans[len] += 2;
			if (ans[len] >= 3) {
				puts("Yes");
				exit(0);
			}
			return;
		}
		c[from].emplace_back(make_pair(pos, len), ++em);
		c[pos].emplace_back(make_pair(from, len), em);
		return;
	}
	int dest = *b[pos].begin();
	rebuild(from, pos, dest, len + 1);
}
void dfs(int pos) {
	vis[pos] = true;
	v++, e += b[pos].size();
	for (auto x : b[pos])
		if (!vis[x]) dfs(x);
}
void work(int pos, int from, int depth) {
	if (depth && pos == from) {
		if (++ans[depth] >= 3) {
			puts("Yes");
			exit(0);
		}
		return;
	}
	if ((clock() - start) >= 1.5 * CLOCKS_PER_SEC) {
		puts("No");
		exit(0);
	}
	while (!c[pos].empty() && rk[c[pos].back().first.first] < rk[from]) c[pos].pop_back();
	for (unsigned i = 0; i < c[pos].size(); i++) {
		pair <pair <int, int>, int> x = c[pos][i];
		if (!vise[x.second] && !vis[x.first.first]) {
			vise[x.second] = vis[x.first.first] = true;
			work(x.first.first, from, depth + x.first.second);
			vise[x.second] = vis[x.first.first] = false;
		}
	}
}
int main() {
	read(n), read(m), start = clock();
	for (int i = 1; i <= m; i++) {
		read(x[i]), read(y[i]);
		a[x[i]].push_back(y[i]);
		a[y[i]].push_back(x[i]);
	}
	for (int i = 1; i <= n; i++) {
		if (dfn[i] == 0) {
			v = 0, e = 0;
			tarjan(i, 0);
			if (e / 2 >= v + sqrt(v) + 2) {
				puts("Yes");
				return 0;
			}
		}
	}
	for (int i = 1; i <= m; i++)
		if (belong[x[i]] == belong[y[i]]) {
			b[x[i]].insert(y[i]);
			b[y[i]].insert(x[i]);
		}
	for (int i = 1; i <= n; i++) {
		iskey[i] = b[i].size() >= 3;
		if (!vis[i]) {
			v = 0, e = 0, dfs(i);
			if (e == 2 * v) {
				ans[v] += 2;
				if (ans[v] >= 3) {
					puts("Yes");
					return 0;
				}
			}
		}
	}
	for (int i = 1; i <= n; i++)
		if (iskey[i]) {
			while (!b[i].empty()) {
				int dest = *b[i].begin();
				rebuild(i, i, dest, 1);
			}
		}
	for (int i = 1; i <= n; i++)
		p[i] = i, rd[i] = i;
	random_shuffle(rd + 1, rd + n + 1);
	sort(p + 1, p + n + 1, cmp);
	for (int i = 1; i <= n; i++)
		rk[p[i]] = i;
	for (int i = 1; i <= n; i++) {
		sort(c[i].begin(), c[i].end(), cnp);
		reverse(c[i].begin(), c[i].end());
	}
	memset(vis, false, sizeof(vis));
	for (int i = 1; i <= n; i++)
		work(p[i], p[i], 0);
	puts("No");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/89787306