*题解: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;
}

浙公网安备 33010602011771号