[CF757F] Team Rocket Rises Again [最短路樹][支配樹]
阿新 • • 發佈:2018-11-12
[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)