luogu P7520 [省选联考 2021 A 卷] 支配
https://www.luogu.com.cn/problem/P7520
如果当时我会支配树我就乱杀了吧
首先肯定是先建出一棵支配树,然后发现,如果一个点的受支配集变化了,那么它子树内所有点的受支配集都会变化
考虑什么情况下这个点的受支配集会产生变化
假设加入的边是\(x->y\)
对于节点\(u\),如果删掉了\(fa[u]\),\(1\)还可以到达\(x\),并且删掉后\(y\)还能到达\(u\)那么\(u\)的受支配集就产生了变化
然后最后把子树的全部标记一下即可
code:
#include<bits/stdc++.h>
#define N 3005
using namespace std;
int dfn[N], id[N], tot, f[N][N], ff[N][N], fa[N];
vector<int> g[N], gr[N];
void pre(int u) {
dfn[u] = ++ tot; id[tot] = u;
for(int v : g[u]) if(!dfn[v]) pre(v);
}
void dfs(int u, int x) {
if(u == x) return ;
f[u][x] = 1;
for(int v : g[u]) if(!f[v][x]) dfs(v, x);
}
void dfss(int u, int x) {
if(u == fa[x]) return ;
ff[u][x] = 1;
for(int v : gr[u]) if(!ff[v][x]) dfss(v, x);
}
int n, m, q, siz[N], ha[N];
int main() {
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
scanf("%d%d%d", &n, &m, &q);
for(int i = 1; i <= m; i ++) {
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v), gr[v].push_back(u);
}
pre(1);
for(int i = 1; i <= n; i ++) dfs(1, i), siz[i] = 1;
for(int i = 1; i <= n; i ++) {
int x = id[i];
for(int j = i - 1; j >= 1; j --) {
int y = id[j];
if(!f[x][y]) {
fa[x] = y;
break;
}
}
}
for(int i = n; i > 1; i --) {
int x = id[i];
siz[fa[x]] += siz[x];
}
for(int i = 1; i <= n; i ++) dfss(i, i);
while(q --) {
int x, y;
scanf("%d%d", &x, &y);
for(int i = 1; i <= n; i ++) ha[i] = 0;
for(int i = 1; i <= n; i ++)
if(fa[i] != 1 && fa[i] != x && f[x][fa[i]] && ff[y][i]) ha[i] = 1;
int ans = 0;
for(int i = 1; i <= n; i ++) {
int x = id[i];
ha[x] |= ha[fa[x]];
}
for(int i = 1; i <= n; i ++) ans += ha[i];
printf("%d\n", ans);
}
return 0;
}