[KaTeX parse error: Expected 'EOF', got '\fark' at position 1: \̲f̲a̲r̲k̲{Link}]
题意:给一 点 边无向图。给出点 。选一个点 使删掉点 后,有尽可能多的点到 的最短距离改变。
考虑一下跑一个
作起点的最短路
。
题目要求变成选一个子树大小最大的割点。 是吗?
这是 ,而不是树。
删掉一个割点并不能让它“子树”内的每一个点都不跟 联通,比如说
这个时候删掉 会让 独立出来,所以 确实是割点,然而删掉它, 还能到达 。
更何况可能图里面根本就不存在割点。。(比如一个环)
所以这个时候我们要求的是有向无环图的支配树。
这个不像有向图里面的那么麻烦,
一次,对一个点
,找到所有能够到达它的点
。
求出这些点的
。
然后就可以在
上面把
连一条边。
最后在
上面找根的儿子里面
最大那个就可以啦。
实际操作嫌麻烦的话求根以外所有点的也可以。(当然如果没有实际建支配树就一定得这么做了)
求
的话,不需要在求
之前预处理
的
。(如果倍增)
因为求
是按照拓扑序的。用到的都是已经求过的。
#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