《P2597 [ZJOI2012]灾难》

这里是个DAG,可以利用类似倍增的做法。

但是可以直接支配树做,建立一个虚点向所有的起点,然后支配树就即可。

// Author: levil
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 2e5 + 5;
const int M = 5e5 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e16
#define dbg(ax) cout << "now this num is " << ax << endl;

int n,val[N],dfn[N],semi[N],idom[N],rk[N],fa[N],out[N],sz[N],tim = 0;
vector<int> G[N],RG[N],T[N];
namespace Node{
    int fa[N],val[N];
    void init() {
        for(int i = 1;i <= n + 1;++i) fa[i] = i;
    }
    int Find(int x) {
        if(x == fa[x]) return x;
        int ffa = fa[x];
        fa[x] = Find(fa[x]);
        if(dfn[semi[val[x]]] > dfn[semi[val[ffa]]]) val[x] = val[ffa];
        return ffa;
    }
    void Merge(int x,int y) {
        x = Find(x),y = Find(y);
        fa[y] = x;
    }
};
void dfs(int u) {
    dfn[u] = ++tim;
    rk[tim] = u;
    for(auto v : G[u]) {
        if(!dfn[v]) {
            fa[v] = u;
            dfs(v);
        }
    }
}
int getmin(int x,int y) {
    return dfn[x] < dfn[y] ? x : y;
}
void solve() {
    dfs(n + 1);
    dfn[0] = tim + 1;
    Node::init();
    for(int i = n + 1;i >= 1;--i) {
        int x = rk[i];
        for(auto v : RG[x]) {
            if(dfn[v] < dfn[x]) semi[x] = getmin(semi[x],v);
            else {
                Node::Find(v);    
                semi[x] = getmin(semi[x],semi[Node::val[v]]);
            }
        }
        for(auto v : T[x]) {
            Node::Find(v);
            int ma = Node::val[v];
            if(semi[ma] == x) idom[v] = x;
            else idom[v] = ma;
        }
        Node::val[x] = x;
        Node::Merge(fa[x],x);
        T[semi[x]].push_back(x);
    }
    for(int i = 2;i <= n + 1;++i) {
        int x = rk[i];
        if(idom[x] != semi[x]) idom[x] = idom[idom[x]];
    }
    for(int i = n + 1;i >= 2;--i) {
        int x = rk[i];
        ++sz[x];    
        if(idom[x]) sz[idom[x]] += sz[x];
    }
}
int main() {
    scanf("%d",&n);
    for(int i = 1;i <= n;++i) {
        int x;
        while(scanf("%d",&x),x != 0) {
            G[x].push_back(i);
            RG[i].push_back(x);
            out[i]++;
        }
    }
    for(int i = 1;i <= n;++i) {
        if(out[i] == 0) {
            G[n + 1].push_back(i);
            RG[i].push_back(n + 1);
        }
    }
    solve();
    for(int i = 1;i <= n;++i) printf("%d\n",sz[i] - 1);
    system("pause");
    return 0;
}
View Code

 

posted @ 2021-08-17 20:41  levill  阅读(38)  评论(0编辑  收藏  举报