这道题真的是神思路,不看题解真的是做不出来,我们这样想,我们首先看得出这是一个拓扑图,但是由于拓扑图可能有多个起点和重点,我们搞一个超级源点和超级汇点,这样答案就变成了超级源点到超级汇点的最长路。我们将这个拓扑图分成两个集合,那么这两个集合之间的连边就一定包括当前图的最大路径(因为这条路径必跨越两个集合),那么我们只要维护这两个集合就可以了。我们可以先预处理出来一个f数组和一个g数组,分别代表一个点到超级源和超级汇的最短路,我们就可以给每条边附上一个权值,权值为这条边左端点到超级源的距离和右端点到超级汇的距离加和再加1,这样一条边即可表示经过这条边的最长路,那么两个集合之间只需要一些边来表示不同的路径条数就可以了,那么我们怎么弄最方便呢?:按照拓扑序一个一个把点从右面的集合放到左面的集合是最方便的,那么我们先将所有的g数组加入到一个大根堆中,按照拓扑序每次枚举一个点将其删掉,具体做法是删除g[i],删除所有指向g[i]的边,然后取一个最大值记为删除i这个点的答案,然后加入f[i](因为可能删着删着就会出现路径不连通的现象),再加入所有左端点为i的边(可以手动模拟下,就会明白上面所说的意思),这样找到一个最小的答案输出即可。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
struct bian
{
int l,r;
}a[5000000];
int ans_len=0x3f3f3f3f;
int ans;
int fir[5000000];
int _fir[5000000];
int nex[5000000];
int tot=0;
void add_edge(int first[],int l,int r)
{
a[++tot].l=l;
a[tot].r=r;
nex[tot]=first[l];
first[l]=tot;
}
struct Priority_queue
{
int dui[1000000];
int sum[1000000];
int top;
Priority_queue()
{
top=0;
}
void Delete(int v)
{
sum[v]--;
}
void Push(int v)
{
if(sum[v]) sum[v]++;
else
{
sum[v]++;
dui[++top]=v;
int i=top;
while(i>1)
{
int j=i>>1;
if(dui[i]>dui[j]) swap(dui[i],dui[j]),i=j;
else break;
}
}
return;
}
void Pop()
{
dui[1]=dui[top];
top--;
int i=1;
while(i*2<=top)
{
int j=i*2;
if(j+1<=top && dui[j+1]>dui[j]) j++;
if(dui[i]<dui[j]) swap(dui[i],dui[j]),i=j;
else break;
}
return;
}
int Top()
{
while(!sum[dui[1]]) Pop();
return dui[1];
}
}my_queue;
int tuo[1000000];
int rudu[1000000];
int top=1,my_final=1;
int n;
void toposort()
{
for(int i=1;i<=n;i++)
if(!rudu[i])
tuo[my_final++]=i;
while(top<my_final)
{
int u=tuo[top++];
for(int o=fir[u];o;o=nex[o])
{
rudu[a[o].r]--;
if(!rudu[a[o].r]) tuo[my_final++]=a[o].r;
}
}
top=my_final-1;
}
int f[1000000];
int g[1000000];
int main()
{
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
rudu[r]++;
add_edge(fir,l,r);
add_edge(_fir,r,l);
}
toposort();
for(int i=1;i<=top;i++)
{
int u=tuo[i];
f[u]=max(f[u],1);
for(int o=fir[u];o;o=nex[o]) if(f[a[o].r]=max(f[u]+1,f[a[o].r]));
}
for(int i=top;i>=1;i--)
{
int u=tuo[i];
g[u]=max(g[u],1);
for(int o=fir[u];o;o=nex[o]) g[u]=max(g[a[o].r]+1,g[u]);
}
for(int i=1;i<=top;i++) my_queue.Push(g[i]);
my_queue.Push(0);
for(int i=1;i<=top;i++)
{
int u=tuo[i];
my_queue.Delete(g[u]);
for(int o=_fir[u];o;o=nex[o])
my_queue.Delete(f[a[o].r]+g[a[o].l]);
if(my_queue.Top()<ans_len) ans_len=my_queue.Top(),ans=u;
my_queue.Push(f[u]);
for(int o=fir[u];o;o=nex[o])
my_queue.Push(f[a[o].l]+g[a[o].r]);
}
cout<<ans<<" "<<ans_len-1<<endl;
}