题解:AT_agc076_c [AGC076C] Slime Eat Slime
参考了官方题解。
题意:给出一个图,再给出每个点的权 \(0\le a_u\le 2K\),如果相邻两个点 \(u,v\) 满足 \((a_u-a_v)\bmod (2K+1) \ge K+1\),那么 \(u\) 就可以把 \(v\) 干掉,问最后是否可以把 \(1\) 号点留下。\(\sum n,m\le 2.5\times 10^5\)。
做法:
不妨令 \(a_1 = 0\)。
感觉看上去完全没啥入手点,我们不妨先把 \(1\) 号点拉出来,那么剩余的图会被划分成若干个连通块,那么我们希望是每个连通块内部打完之后,剩下的都被 \(1\) 干掉,这样就可以了。
那么我们会这么想:每个连通块选出来若干个点给 \(1\) 干掉,然后给 \(1\) 干掉的那些点再递归去让他们干掉别的点,一层层下去,但是这样显然太难做了,每次要选择的点完全无法刻画。实际上我们发现,只需要考虑一层点就可以了。我们接下来对于一个连通块考虑。
我们注意到 \(1\) 可以干掉的是 \([1,K]\),假设有一个方案,我们就拉出来一个点 \(u\) 满足 \(a_u\in [1,K]\) 且 \(a_u\) 最大,他就可以帮我们干掉 \([a_u+1,a_u+K]\) 的部分。我们考虑把点 \(u\) 作为我们被 \(1\) 干掉的点,这里我们不要求 \(a_u\) 最大,任意都可以。那么我们把 \(u\) 扔掉之后这个连通块会变成若干个小连通块,这些连通块就得满足一些条件才行:
-
\(a\) 全都在 \([1,K]\) 内。
-
如果不满足上面这条,则必须满足存在于一个在 \([K+1, a_u+K]\) 的点,否则如果 \(a_u \ge K+1\) 的点全在 \([a_u+K+1,2K]\) 这一部分,这些点最后一定会剩下一个没法被干掉。
这些是必要条件,我们考虑证明他同时是充分的。
我们称 \(a_v\in [1,K]\) 的点 \(v\) 为 A 类点,\(a_v\in [K+1,a_u+K]\) 的称为 B 类点,\(a_v\in [a_u+K+1,2K+1]\) 的称为 C 类点。
如果全都是 A 类点,显然全用 \(1\) 干掉就可以了。
否则我们考虑我们需要干掉所有的 C 类点才能合法,我们发现只要我们不让 A 类点去干掉 B 类点,让 C 类点去随便和非 C 类点进行操作,我们发现 B 类点一定不会被干掉,这样最后会剩下若干 A 类点和 B 类点,我们让 \(1,u\) 去干掉就可以了。
那么现在就是怎么 check 一个点 \(u\) 合法不合法,发现这跟扔掉一个点之后拆出来的连通块有关,所以我们考虑建出来圆方树,我们可以把圆点作为答案,然后就是要检验自己的子树和外面的子树是否满足全为 A 类点或者存在 B 类点了,这个换根随便维护即可,复杂度 \(O(n+m)\)。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5;
int n, m, tot, dfn[maxn], low[maxn], idx, pos[maxn], st[maxn], top, k, c[maxn];
vector<int> e[maxn], g[maxn];
void clear() {
for (int i = 1; i <= 2 * n; i++)
dfn[i] = low[i] = pos[i] = st[i] = 0, e[i].clear(), g[i].clear();
top = idx = tot = 0;
}
int all;
void tarjan(int u, int fa) {
dfn[u] = low[u] = ++idx; st[++top] = u; all++;
for (int i = 0; i < e[u].size(); i++) {
int v = e[u][i];
if(v == fa)
continue;
if(!dfn[v]) {
tarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) {
tot++;
while(1) {
int p = st[top--];
g[tot].push_back(p), g[p].push_back(tot);
if(p == v)
break;
}
int p = u;
g[tot].push_back(p), g[p].push_back(tot);
}
}
else
low[u] = min(low[u], dfn[v]);
}
}
int sz[maxn], mn[maxn], smn[maxn], p[maxn], val[maxn], ct[maxn], al[maxn];
void dfs1(int u, int fa) {
sz[u] = ct[u] = (u <= n && (c[u] >= 1 && c[u] <= k)); al[u] = (u <= n);
val[u] = (u <= n && (c[u] >= k + 1 && c[u] <= 2 * k + 1) ? c[u] : 2 * k + 2);
mn[u] = val[u], smn[u] = 2 * k + 2; p[u] = u;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if(v == fa)
continue;
dfs1(v, u);
if(mn[v] < smn[u])
smn[u] = mn[v];
if(smn[u] < mn[u])
p[u] = v, swap(smn[u], mn[u]);
sz[u] += sz[v], al[u] += al[v];
}
// cout << u << " " << fa << " " << al[u] << " " << sz[u] << " " << c[u] << " " << k << " " << mn[u] << endl;
}
bool chk(int u, int fa, int mnv, int cnt) {
if(!ct[u])
return 0;
int f = (cnt == all - al[u] || mnv <= c[u] + k);
// cout << u << " " << f << " " << all - al[u] << " " << cnt << endl;
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if(v == fa)
continue;
f &= (al[v] == sz[v] || mn[v] <= c[u] + k);
}
return f;
}
bool dfs2(int u, int fa, int mnv, int cnt) {
if(chk(u, fa, mnv, cnt))
return 1;
mnv = min(mnv, val[u]);
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if(v == fa)
continue;
if(dfs2(v, u, min(mnv, (p[u] == g[u][i] ? smn[u] : mn[u])), cnt + sz[u] - sz[v]))
return 1;
}
return 0;
}
bool solve(int u) {
all = 0;
tarjan(u, 0);
dfs1(u, 0);
if(dfs2(u, 0, 2 * k + 2, 0))
return 1;
return 0;
}
int cnt = 0;
void solve() {
cnt++;
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
cin >> c[i];
for (int i = n; i >= 1; i--)
c[i] = (c[i] - c[1] + 2 * k + 1) % (2 * k + 1);
for (int i = 2; i <= n; i++)
if(c[i] == 0)
c[i] = 2 * k + 1;
// for (int i = 1; i <= n; i++)
// cout << c[i] << " ";
// cout << endl;
clear();
tot = n;
for (int i = 1; i <= m; i++) {
int x, y; cin >> x >> y;
if(x > y)
swap(x, y);
if(x == 1)
e[x].push_back(y);
else
e[x].push_back(y),
e[y].push_back(x);
}
for (int i = 0; i < e[1].size(); i++)
if(!dfn[e[1][i]]) {
if(!solve(e[1][i])) {
cout << "No" << endl;
return ;
}
}
cout << "Yes" << endl;
return ;
}
signed main() {
// freopen("test.in", "r", stdin);
// freopen("std.out", "w", stdout);
int T; cin >> T;
while(T--)
solve();
return 0;
}
/*
1
5 8 10
5 6 10 8 19
1 2
1 3
1 4
1 5
2 3
2 4
3 4
3 5
*/

浙公网安备 33010602011771号