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;
}
posted @ 2022-02-16 15:32  lahlah  阅读(31)  评论(0编辑  收藏  举报