题目
[CodeForces 757F] Team Rocket Rises Again
分析
建出最短路径图(是个 DAG)的支配树,找到除起点外支配的点最多的点即可。
错因
Tid
打成Dfn
;- 用链式前向星,
To
和Next
数组的大小没有开到 ; - 以为是求要删的点(样例还能过)。
代码
#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;
}