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

4 篇文章 0 订阅
1 篇文章 0 订阅

f ( u ) f(u) f(u) 表示从节点 u u u 出发的最长路, g ( u ) g(u) g(u) 表示到 u u u 结束的最长路,这两个 d p dp dp 的转移都比较显然,就不说了。那么经过一条边 ( u , v ) (u,v) (u,v) 的最长路就是 g ( u ) + 1 + f ( v ) g(u) + 1 + f(v) g(u)+1+f(v)

o r d u ord_u ordu 表示节点 u u u 的拓扑序。

删去了一个节点 u u u 之后,我们将节点按照拓扑序分成两部分 A , B A,B A,B, 其中 A A A 的节点的拓扑序小于 o r d u ord_u ordu 的, B B B 中节点的拓扑序都是大于 o r d u ord_u ordu 的。

那么答案显然只有三种情况可选:

  1. A A A 内部的,也就是 max ⁡ u ∈ A { g ( u ) } \max\limits_{u \in A} \{ g(u) \} uAmax{g(u)}
  2. B B B 内部的, max ⁡ u ∈ B { f ( u ) } \max\limits_{u \in B} \{f(u)\} uBmax{f(u)}
  3. A A A 连向 B B B 的, max ⁡ ( u , v ) ∈ E , u ∈ A , v ∈ B { g ( u ) + 1 + f ( v ) } \max\limits_{(u,v) \in E, u \in A, v \in B} \{g(u)+1+f(v)\} (u,v)E,uA,vBmax{g(u)+1+f(v)}

现在我们可以考虑统计完删除 u u u 的情况之后,将信息更新至删除 u ′   ( o r d u ′ = o r d u + 1 ) u'~(ord_{u'}=ord_{u}+1) u (ordu=ordu+1) 的情况。为了完成这件事,我们需要一个可删堆(当然其他数据结构也行,但是这个代码短)。

起始的时候,所有节点都在 B B B 中,也就是将所有 f ( u ) f(u) f(u) 都加到堆中。接着,我们考虑按照拓扑序从小到大,删除一个节点 u u u 的相关信息,然后再将 u u u 放到 A A A 中。

首先是删除 u u u 的信息。删除 f ( u ) f(u) f(u) , 接着删除经过 ( v , u )   ( v ∈ A ) (v,u)~(v\in A) (v,u) (vA) 的最长路,就可以了(雾)。

接着加回所有 u u u 的信息,首先加入 g ( u ) g(u) g(u), 接着加入经过 ( u , v )   ( v ∈ B ) (u,v)~(v\in B) (u,v) (vB) 的最长路。

那么最终的代码如下:

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值