[CodeForces 757F] Team Rocket Rises Again(最短路徑圖 + 支配樹) | 錯題本

題目

[CodeForces 757F] Team Rocket Rises Again

分析

建出最短路徑圖(是個 DAG)的支配樹,找到除起點外支配的點最多的點即可。

錯因

  • Tid 打成 Dfn
  • 用鏈式前向星,ToNext 數組的大小沒有開到 mm
  • 以爲是求要刪的點(樣例還能過)。

代碼

#include <bits/stdc++.h>

typedef long long LL;
typedef std::pair<int, int> PII;

const int MAXN = 200000;
const int MAXM = 300000;

int N, M, S;
std::vector<PII> F[MAXN + 5];

struct Graph {
    int EdgeCnt, Adj[MAXN + 5], To[MAXM + 5], Next[MAXM + 5];

    void Init() { EdgeCnt = 0; memset(Adj, -1, sizeof Adj); }

    void AddEdge(int u, int v) { To[++EdgeCnt] = v, Next[EdgeCnt] = Adj[u], Adj[u] = EdgeCnt; }
}G, H, STree, ITree;

int DfnCnt;
int Fat[MAXN + 5];
int Dfn[MAXN + 5], Tid[MAXN + 5];
int SDom[MAXN + 5], IDom[MAXN + 5];

struct Union_Find {
    int Fat[MAXN + 5], Min[MAXN + 5];

    void Init(int n) {
        for (int i = 1; i <= n; i++)
            Fat[i] = Min[i] = i;
    }

    int Find(int u) {
        if (Fat[u] == u)
            return u;
        int anc = Find(Fat[u]);
        if (Dfn[SDom[Min[Fat[u]]]] < Dfn[SDom[Min[u]]])
            Min[u] = Min[Fat[u]];
        return Fat[u] = anc;
    }
}T;

struct Node {
    int u; LL d;

    Node(int _u = 0, LL _d = 0) { u = _u, d = _d; }

    bool operator < (const Node &other) const { return d > other.d; }
};

LL Dist[MAXN + 5];

void Dijkstra(int S) {
    std::priority_queue<Node> Q;
    memset(Dist, 0x3f, sizeof Dist);
    Q.push(Node(S, Dist[S] = 0));
    while (!Q.empty()) {
        int u = Q.top().u; LL d = Q.top().d; Q.pop();
        if (d < Dist[u]) continue;
        for (int i = 0; i < int(F[u].size()); i++) {
            int v = F[u][i].first, w = F[u][i].second;
            if (Dist[v] > Dist[u] + w)
                Q.push(Node(v, Dist[v] = Dist[u] + w));
        }
    }
}

void Dfs(int u) {
    Tid[Dfn[u] = ++DfnCnt] = u;
    for (int i = G.Adj[u]; ~i; i = G.Next[i]) {
        int v = G.To[i];
        if (!Dfn[v])
            Fat[v] = u, Dfs(v);
    }
}

void Lengauer_Tarjan() {
    T.Init(N);
    for (int i = 1; i <= N; i++)
        SDom[i] = i;
    for (int i = DfnCnt; i >= 2; i--) {
        int u = Tid[i];
        for (int j = H.Adj[u]; ~j; j = H.Next[j]) {
            int v = H.To[j];
            if (Dfn[v]) {
                T.Find(v);
                if (Dfn[SDom[T.Min[v]]] < Dfn[SDom[u]])
                    SDom[u] = SDom[T.Min[v]];
            }
        }
        STree.AddEdge(SDom[u], u);
        int r = T.Fat[u] = Fat[u];
        for (int j = STree.Adj[r]; ~j; j = STree.Next[j]) {
            int v = STree.To[j];
            T.Find(v);
            if (SDom[T.Min[v]] == r)
                IDom[v] = r;
            else
                IDom[v] = T.Min[v];
        }
        STree.Adj[r] = -1;
    }
    for (int i = 2; i <= DfnCnt; i++) {
        int u = Tid[i];
        if (IDom[u] != SDom[u])
            IDom[u] = IDom[IDom[u]];
    }
}

int Size[MAXN + 5];

void Count(int u) {
    Size[u] = 1;
    for (int i = ITree.Adj[u]; ~i; i = ITree.Next[i]) {
        int v = ITree.To[i];
        Count(v);
        Size[u] += Size[v];
    }
}

int main() {
    scanf("%d%d%d", &N, &M, &S);
    for (int i = 1; i <= M; i++) {
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        F[u].push_back(std::make_pair(v, w));
        F[v].push_back(std::make_pair(u, w));
    }
    Dijkstra(S);
    G.Init(), H.Init(), STree.Init(), ITree.Init();
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j < int(F[i].size()); j++) {
            int v = F[i][j].first, w = F[i][j].second;
            if (Dist[v] == Dist[i] + w) {
                G.AddEdge(i, v);
                H.AddEdge(v, i);
            }
        }
    }
    Dfs(S);
    Lengauer_Tarjan();
    for (int i = 1; i <= N; i++)
        if (IDom[i])
            ITree.AddEdge(IDom[i], i);
    Count(S);
    int Ans = 0;
    for (int i = 1; i <= N; i++)
        if (i != S)
            Ans = std::max(Ans, Size[i]);
    printf("%d", Ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章