题意:给一 n \mathcal{n} n点 m \mathcal{m} m边无向图。给出点 S \mathcal{S} S。选一个点 u ≠ S \mathcal{u\ne S} u̸=S使删掉点 u \mathcal{u} u后,有尽可能多的点到 S \mathcal{S} S的最短距离改变。
考虑一下跑一个
S
\mathcal{S}
S作起点的最短路
D
A
G
\mathcal{DAG}
DAG。
题目要求变成选一个子树大小最大的割点。 是吗?
这是 D A G \mathcal{DAG} DAG,而不是树。
删掉一个割点并不能让它“子树”内的每一个点都不跟 S \mathcal{S} S联通,比如说 s → u , u → v , v → w , u → w , v → o \mathcal{s\to u,u\to v,v\to w,u\to w,v\to o} s→u,u→v,v→w,u→w,v→o
这个时候删掉 v \mathcal{v} v会让 o \mathcal{o} o独立出来,所以 v \mathcal{v} v确实是割点,然而删掉它, S \mathcal{S} S还能到达 w \mathcal{w} w。
更何况可能图里面根本就不存在割点。。(比如一个环)
所以这个时候我们要求的是有向无环图的支配树。
这个不像有向图里面的那么麻烦,
t
o
p
o
s
o
r
t
\mathcal{toposort}
toposort一次,对一个点
v
\mathcal{v}
v,找到所有能够到达它的点
x
\mathcal{x}
x。
求出这些点的
l
c
a
:
u
\mathcal{lca:u}
lca:u。
然后就可以在
D
o
m
i
n
a
t
o
r
  
T
r
e
e
\mathcal{Dominator\;Tree}
DominatorTree上面把
u
→
v
\mathcal{u\to v}
u→v连一条边。
最后在
D
o
m
i
n
a
t
o
r
  
T
r
e
e
\mathcal{Dominator\;Tree}
DominatorTree上面找根的儿子里面
s
i
z
\mathcal{siz}
siz最大那个就可以啦。
实际操作嫌麻烦的话求根以外所有点的也可以。(当然如果没有实际建支配树就一定得这么做了)
求
L
C
A
\mathcal{LCA}
LCA的话,不需要在求
D
o
m
i
n
a
t
o
r
  
T
r
e
e
\mathcal{Dominator\;Tree}
DominatorTree之前预处理
D
A
G
\mathcal{DAG}
DAG的
p
r
e
[
i
]
[
x
]
\mathcal{pre[i][x]}
pre[i][x]。(如果倍增)
因为求
D
o
m
i
n
a
t
o
r
  
T
r
e
e
\mathcal{Dominator\;Tree}
DominatorTree是按照拓扑序的。用到的都是已经求过的。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
using namespace std;
#define add_edge(a,b,c) nxt[++tot]=head[a],head[a]=tot,to[tot]=b,val[tot]=c
#define add_up(a,b,c) upnxt[++uptot]=uphead[a],uphead[a]=uptot,upto[uptot]=b
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<12], *frS=frBB, *frT=frBB;
int read() {
int x = 0;
char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
return x;
}
int head[200015];
int nxt[600015];
int to[600015];
int u[300015];
int v[300015];
int w[300015];
int val[600015];
long long dis[200015];
int pre[200015][25];
int uphead[200015];
int upnxt[300015];
int upto[300015];
int deg[200015];
int siz[200015];
int qwq[200015];
int dep[200015];
bool vis[200015];
int n, m, s, tot, uptot, loglog;
#define PII pair<long long, int>
priority_queue<PII, vector<PII>, greater<PII> > QvQ;
void dijkstra() {
for (register int i = 1; i <= n; ++i) dis[i] = 2147483647147483647ll;
dis[s] = 0;
QvQ.push(make_pair(0, s));
int cnt = 0;
while (!QvQ.empty()) {
++cnt;
int x = QvQ.top().second;
QvQ.pop();
vis[x] = 1;
for (register int i = head[x]; i; i = nxt[i]) {
if (dis[to[i]] <= dis[x] + val[i]) continue;
dis[to[i]] = dis[x] + val[i];
if (vis[to[i]]) continue;
QvQ.push(make_pair(dis[to[i]], to[i]));
}
}
}
void Toposort() {
qwq[++qwq[0]] = s;
int qwqhead = 0;
while (qwq[0] != qwqhead) {
int x = qwq[++qwqhead];
for (register int i = head[x]; i; i = nxt[i]) {
--deg[to[i]];
if (!deg[to[i]]) {
qwq[++qwq[0]] = to[i];
}
}
}
n = qwq[0];
}
int Doubly(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (register int i = loglog; i >= 0; --i) {
if (dep[pre[x][i]] >= dep[y]) {
x = pre[x][i];
}
}
if (x == y) return x;
for (register int i = loglog; i >= 0; --i) {
if (pre[x][i] != pre[y][i]) {
x = pre[x][i];
y = pre[y][i];
}
}
return pre[x][0];
}
void DominatorTree() {
dep[s] = 1;
for (register int i = 2; i <= n; ++i) {
int t(0);
int x(qwq[i]);
for (int j = uphead[x]; j; j = upnxt[j]) {
if (!t) t = upto[j];
else t = Doubly(t, upto[j]);
}
pre[x][0] = t;
dep[x] = dep[t] + 1;
for (int j = 1; j <= loglog; ++j) {
pre[x][j] = pre[pre[x][j-1]][j-1];
}
}
}
int main() {
n = read();
m = read();
s = read();
loglog = (int) (log(1.0 * n) / log(2.0)) + 1;
for (int i = 1; i <= m; ++i) {
u[i] = read();
v[i] = read();
w[i] = read();
add_edge(u[i], v[i], w[i]);
add_edge(v[i], u[i], w[i]);
}
dijkstra();
tot = 0;
for (register int i = 1; i <= n; ++i) {
head[i] = 0;
}
for (register int i = 1; i <= m; ++i) {
if (dis[u[i]] > dis[v[i]]) swap(u[i], v[i]);
if (dis[u[i]] + w[i] == dis[v[i]]) {
add_edge(u[i], v[i], w[i]);
++deg[v[i]];
add_up(v[i], u[i], w[i]);
}
}
Toposort();
for (register int i = loglog; i >= 0; --i) pre[s][i] = s;
DominatorTree();
for (int i = n; i > 1; --i) {
siz[pre[qwq[i]][0]] += ++siz[qwq[i]];
}
int ans = 0;
for (register int i = 2; i <= n; ++i) {
ans = max(ans, siz[qwq[i]]);
}
printf("%d", ans);
return 0;
}
99行第一个j被我打成了i调了半天,自闭了
dijkstra的dis[to[i]]<=被我打成了dis[to[i]]< 自闭闭了
注意开long long