1. 程式人生 > >[CF757F] Team Rocket Rises Again [最短路樹][支配樹]

[CF757F] Team Rocket Rises Again [最短路樹][支配樹]

[KaTeX parse error: Expected 'EOF', got '\fark' at position 1: \̲f̲a̲r̲k̲{Link}]


題意:給一 n \mathcal{n} m \mathcal{m}

邊無向圖。給出點 S \mathcal{S} 。選一個點 u S \mathcal{u\ne S}
使刪掉點 u \mathcal{u} 後,有儘可能多的點到 S \mathcal{S} 的最短距離改變。


考慮一下跑一個 S

\mathcal{S} 作起點的最短路 D A G \mathcal{DAG}
題目要求變成選一個子樹大小最大的割點。 是嗎?

這是 D A G \mathcal{DAG} ,而不是樹。
刪掉一個割點並不能讓它“子樹”內的每一個點都不跟 S \mathcal{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}
這個時候刪掉 v \mathcal{v} 會讓 o \mathcal{o} 獨立出來,所以 v \mathcal{v} 確實是割點,然而刪掉它, S \mathcal{S} 還能到達 w \mathcal{w}
更何況可能圖裡面根本就不存在割點。。(比如一個環)

所以這個時候我們要求的是有向無環圖的支配樹
這個不像有向圖裡面的那麼麻煩, t o p o s o r t \mathcal{toposort} 一次,對一個點 v \mathcal{v} ,找到所有能夠到達它的點 x \mathcal{x}
求出這些點的 l c a : u \mathcal{lca:u}
然後就可以在 D o m i n a t o r    T r e e \mathcal{Dominator\;Tree} 上面把 u v \mathcal{u\to v} 連一條邊。
最後在 D o m i n a t o r    T r e e \mathcal{Dominator\;Tree} 上面找根的兒子裡面 s i z \mathcal{siz} 最大那個就可以啦。
實際操作嫌麻煩的話求根以外所有點的也可以。(當然如果沒有實際建支配樹就一定得這麼做了)
L C A \mathcal{LCA} 的話,不需要在求 D o m i n a t o r    T r e e \mathcal{Dominator\;Tree} 之前預處理 D A G \mathcal{DAG} p r e [ i ] [ x ] \mathcal{pre[i][x]} 。(如果倍增)
因為求 D o m i n a t o r    T r e e \mathcal{Dominator\;Tree} 是按照拓撲序的。用到的都是已經求過的。


#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)