*题解:P3573 [POI 2014] RAJ-Rally

题目链接

解析

看到“最长路径最短”,立刻想单调性,可惜这对于本题来说并没有什么意义。

每删一个点拓扑一次的暴力做法是显然的,我们看看能不能想办法不要拓扑那么多次,这意味着我们需要在删上一个点时保留一些信息下来。

先拓扑一遍,求 \(d_i\) 表示以点 \(i\) 结尾的最长路。

不妨按拓扑序删点,这样所有点就分成了两部分,被删过的点的点集为 \(S_1\),未被删过的点的点集为 \(S_2\)。最长路路径上的点有三种可能,均在 \(S_1\) 内;均在 \(S_2\) 内;以及部分在 \(S_1\) 内,部分在 \(S_2\) 内。我们考虑维护这些路径长度。显然不能全维护,对于第一、二种情况,我们维护以 \(u\) 为终点/起点的最长路。对于第三种情况,对于每条联系着 \(S_1,S_2\) 的边维护经过其的最长路。

具体地,设当前要删的点为 \(u\),那么 \(u\) 会从 \(S_2\) 转移到 \(S_1\)。对于第一种情况,我们有现成的 \(d\),将 \(d_u\) 加入数据结构即可。对于第二种情况,需要再处理一个 \(d'\) 表示以某个点为起点的最长路,然后将 \(d'_u\) 移出数据结构。而对于第三种情况,我们需要将原本联系着 \(S_1\) 和点 \(u\) 的边的贡献删去,并将联系着点 \(u\)\(S_2\) 的边的贡献加上,即对于所有 \(u\) 的入边 \((x,u)\),我们计算经过它的最长路长度 \(d_x + 1 + d'_u\),并将其从数据结构中删去,对于所有 \(u\) 的出边 \((u,y)\),同样计算经过它的最长路 \(d_u + 1 + d'_y\),将其加入数据结构。

于是我们需要一个支持加入指定值,删除指定值,求最大值的数据结构,这里选取的是 multiset。

时间复杂度 \(O(m\log m)\)

代码

#include <bits/stdc++.h>
#define eps 0.0000000001
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<int,int> pii;
const int N = 5e5 + 5,M = 1e6 + 5,P = 2000000,mod = 998244353,mod2 = 1e9 + 7,b1 = 131,b2 = 13331; 
vector<int> g1[N],g2[N];
int ind[3][N];
int head[2][M],to[2][M],nxt[2][M],cnt[2],d[2][N];
void add(int x,int a,int b){
	cnt[x]++;
	to[x][cnt[x]] = b;
	nxt[x][cnt[x]] = head[x][a];
	head[x][a] = cnt[x];
	ind[x][b]++;
	if(x == 0){
		ind[2][b]++;
	}
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		add(0,u,v);
		add(1,v,u);
	}
	queue<int> q;
	for(int i=1;i<=n;i++){
		if(ind[0][i] == 0){
			q.push(i);
		}
	}
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int i = head[0][u];i;i = nxt[0][i]){
			int v = to[0][i];
			d[0][v] = max(d[0][v],d[0][u] + 1);
			ind[0][v]--;
			if(!ind[0][v]){
				q.push(v);
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(ind[1][i] == 0){
			q.push(i);
		}
	}
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int i = head[1][u];i;i = nxt[1][i]){
			int v = to[1][i];
			d[1][v] = max(d[1][v],d[1][u] + 1);
			ind[1][v]--;
			if(!ind[1][v]){
				q.push(v);
			}
		}
	}
	multiset<int> s;
	for(int i=1;i<=n;i++){
		s.insert(d[1][i]);
	}
	for(int i=1;i<=n;i++){
		if(ind[2][i] == 0){
			q.push(i);
		}
	}
	int mn = 2e9,mnp = -1;
	
	while(!q.empty()){
		int u = q.front();
		q.pop();
		for(int i = head[1][u];i;i = nxt[1][i]){
			int v = to[1][i];
			s.erase(s.find(d[0][v] + d[1][u] + 1));
		}
		s.erase(s.find(d[1][u]));
		int x = *prev(s.end());
		if(x < mn){
			mn = x;
			mnp = u;
		}
		for(int i = head[0][u];i;i = nxt[0][i]){
			int v = to[0][i];
			s.insert(d[0][u] + d[1][v] + 1);
		}
		s.insert(d[0][u]);
		for(int i = head[0][u];i;i = nxt[0][i]){
			int v = to[0][i];
			ind[2][v]--;
			if(!ind[2][v]){
				q.push(v);
			}
		}
	}
	cout<<mnp<<" "<<mn;
	return 0;
}
posted @ 2026-06-30 22:04  yutar  阅读(2)  评论(0)    收藏  举报