可爱支配树在线求调
查看原帖
可爱支配树在线求调
632955
伊地知虹夏楼主2023/6/20 14:35
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int n,m,D[N];
int dfn[N], ori[N], tot,FF[N];
int mn[N], fa[N], d[N];
int in[N];
int F[N][21],idom[N];

vector<int> G[N];//原图
vector<int> P[N];//新图(Topo)
vector<int> T[N];//支配树
vector<int> From[N];//反图

void tarjan(int x,int ff){
    dfn[x] = ++tot;
    ori[tot] = x;
    FF[x] = ff;
    if(ff != -1)
        P[ff].push_back(x), in[x]++;
    for (auto y : G[x])
        if(!dfn[y]) 
            tarjan(y,x);
}

void init(){
    for(int i = 1;i <= n;i ++)
        fa[i] = mn[i] = idom[i] = i;
}

int find(int x){
    if(fa[x] == x) return x;
    int p = fa[x];
    fa[x] = find(fa[x]);
    if (dfn[idom[mn[p]]] < dfn[idom[mn[x]]])
        mn[x] = mn[p];
    return fa[x];
}

void get_idom(){
    for(int i = n;i >= 2;i --){
        int x = ori[i],mini = n;
        if(!x)
            continue;
        for (auto y : From[x])
        {
            if(!dfn[y]) continue;
            if(dfn[y] < dfn[x]) mini = min(mini,dfn[y]);
            else find(y),mini = min(mini,dfn[idom[mn[y]]]);
        }
        idom[x] = ori[mini], fa[x] = FF[x];
        P[idom[x]].push_back(x);
        in[x]++;
    }
}

int lca(int x,int y){
    if(d[x] < d[y]) swap(x,y);
    for(int i = 20;i >= 0;i --)
        if(d[F[x][i]] >= d[y])
            x = F[x][i];
    if(x == y) return x;
    for(int i = 20;i >= 0;i --)
        if(F[x][i] != F[y][i])
            x = F[x][i],y = F[y][i];
    return F[x][0];
}

void Topo(){
    queue<int> q;
    for (int i = 1; i <= n;i ++)
        if(in[i] == 0) q.push(i);
    memset(D, -1, sizeof D);
    while (q.size())
    {
        int u = q.front();
        q.pop();
        d[u] = d[D[u]] + 1;
        F[u][0] = D[u];
        for (int i = 1; i <= 20; i++)
            F[u][i] = F[F[u][i - 1]][i - 1];
        T[D[u]].push_back(u);
        for (auto v : P[u])
        {
            if (D[v] == -1)
                D[v] = u;
            else
                D[v] = lca(u, D[v]);
            if (--in[v] == 0)
                q.push(v);
        }
    }
}

int siz[N];
int dfs(int x){
    siz[x] = 1;
    for(auto y:T[x])
        siz[x] += dfs(y);
    return siz[x];
}

signed main(){
    cin >> n >> m;
    for(int i = 1;i <= m;i ++){
        int a,b;
        cin >> a >> b;
        G[a].push_back(b);
        From[b].push_back(a);
    }
    init();
    tarjan(1,-1);
    get_idom();
    Topo();
    dfs(1);
    for(int i = 1;i <= n;i ++)
        cout << siz[i] << ' ';
}

用的是求出半支配点后跑DAG求支配树的写法。

2023/6/20 14:35
加载中...