1. 程式人生 > 其它 >[題解][LG-P3573][POI2014]RAJ-Pally

[題解][LG-P3573][POI2014]RAJ-Pally

\(f(u)\) 表示從節點 \(u\) 出發的最長路,\(g(u)\) 表示到 \(u\) 結束的最長路,這兩個 \(dp\) 的轉移都比較顯然,就不說了。那麼經過一條邊 \((u,v)\) 的最長路就是 \(g(u) + 1 + f(v)\)

\(ord_u\) 表示節點 \(u\) 的拓撲序。

刪去了一個節點 \(u\) 之後,我們將節點按照拓撲序分成兩部分 \(A,B\), 其中 \(A\) 的節點的拓撲序小於 \(ord_u\) 的,\(B\) 中節點的拓撲序都是大於 \(ord_u\) 的。

那麼答案顯然只有三種情況可選:

  1. \(A\) 內部的,也就是 \(\max\limits_{u \in A} \{ g(u) \}\)
  2. \(B\) 內部的,\(\max\limits_{u \in B} \{f(u)\}\)
  3. \(A\) 連向 \(B\) 的,\(\max\limits_{(u,v) \in E, u \in A, v \in B} \{g(u)+1+f(v)\}\)

現在我們可以考慮統計完刪除 \(u\) 的情況之後,將資訊更新至刪除 \(u'~(ord_{u'}=ord_{u}+1)\) 的情況。為了完成這件事,我們需要一個可刪堆(當然其他資料結構也行,但是這個程式碼短)。

起始的時候,所有節點都在 \(B\) 中,也就是將所有 \(f(u)\) 都加到堆中。接著,我們考慮按照拓撲序從小到大,刪除一個節點 \(u\)

的相關資訊,然後再將 \(u\) 放到 \(A\) 中。

首先是刪除 \(u\) 的資訊。刪除 \(f(u)\) , 接著刪除經過 \((v,u)~(v\in A)\) 的最長路,就可以了(霧)。

接著加回所有 \(u\) 的資訊,首先加入 \(g(u)\), 接著加入經過 \((u,v)~(v\in B)\) 的最長路。

那麼最終的程式碼如下:

#include <bits/stdc++.h>

using namespace std;

const int maxn = 5e5 + 5, INF = 1e9;
int read_int() {
	int t = 0; char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while ('0' <= ch && ch <= '9')
		t = (t << 3) + (t << 1) + ch - '0',
		ch = getchar();
	return t;
}
int n;
struct Graph {
	struct Edge {
		int v, nex;
		Edge(int v = 0, int nex = 0) : v(v), nex(nex) {}
	} E[maxn << 1];
	int hd[maxn], deg[maxn], tote;
	void addedge(int u, int v) {
		E[++tote] = Edge(v, hd[u]), hd[u] = tote, deg[v]++;
	}

	int ls[maxn], ls_sz, f[maxn];
	queue<int> q;
	void topo() {
		for (int i = 1; i <= n; i++) if (!deg[i]) q.push(i);
		while (!q.empty()) {
			int u = q.front(); q.pop(), ls[++ls_sz] = u;
			for (int i = hd[u]; i; i = E[i].nex) {
				int v = E[i].v;
				deg[v]--;
				if (!deg[v]) q.push(v);
			}
		}
		for (int p = n; p >= 1; p--) {
			int u = ls[p];
			for (int i = hd[u]; i; i = E[i].nex)
				f[u] = max(f[u], f[E[i].v] + 1);
		}
	}
} G, rG;

struct RbHeap {
	priority_queue<int> q, del_q;
	void push(int val) { q.push(val); }
	void pop(int val) { del_q.push(val); }
	int top() {
		while (del_q.size() && q.top() == del_q.top()) q.pop(), del_q.pop();
		return (q.size() ? q.top() : -INF);
	}
} hp;

int main() {
	int m; n = read_int(), m = read_int();
	for (int i = 1; i <= m; i++) {
		int u = read_int(), v = read_int();
		G.addedge(u, v), rG.addedge(v, u);
	} 
	G.topo(), rG.topo();
	int ans1, ans2;
	for (int i = 1; i <= n; i++) hp.push(G.f[i]);
	ans2 = hp.top();
	for (int p = 1; p <= n; p++) {
		int u = G.ls[p]; hp.pop(G.f[u]);
		for (int i = rG.hd[u]; i; i = rG.E[i].nex) {
			int v = rG.E[i].v;
			hp.pop(rG.f[v] + 1 + G.f[u]);
		}
		int val = hp.top();
		if (val < ans2) ans1 = u, ans2 = val;
		hp.push(rG.f[u]);
		for (int i = G.hd[u]; i; i = G.E[i].nex) {
			int v = G.E[i].v;
			hp.push(rG.f[u] + 1 + G.f[v]);
		}
	}
	printf("%d %d\n", ans1, ans2);
	return 0;
}