[POI2014]RAJ(最短路,拓扑排序)

Posted 1000suns

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POI2014]RAJ(最短路,拓扑排序)相关的知识,希望对你有一定的参考价值。

对于一个点 \(x\) 如何求答案?

由于这个图是个有向无环图,可以先拓扑排序一遍,求出每个点的拓扑序,从起点到它的最长路 \(d2\),从它到终点的最长路 \(d1\)。(我写代码是这么写的,注意顺序)

把拓扑序比小 \(x\) 的点的点集叫 \(A\),大的叫 \(B\)。答案就是 \(\max\limitsu\in A,v\in B(d2_u+d1_v+w_(u,v))\)

发现当 \(x\) 的拓扑序变大 \(1\) 时,集合 \(A\) 会多一个数,集合 \(B\) 会少一个数。

可以动态维护最大值。

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

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int maxn=1000100;
#define MP make_pair
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read()
    int x=0,f=0;char ch=getchar();
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;

int n,m,el,ans1,ans2=2e9,head[maxn],to[maxn],nxt[maxn],el2,head2[maxn],to2[maxn],nxt2[maxn],deg[maxn],id[maxn],cnt,seq[maxn],q[maxn],h,r,d1[maxn],d2[maxn];
multiset<int,greater<int> > fuck;
inline void add(int u,int v)
    to[++el]=v;nxt[el]=head[u];head[u]=el;

inline void add2(int u,int v)
    to2[++el2]=v;nxt2[el2]=head2[u];head2[u]=el2;

int dfs(int u)
    if(~d1[u]) return d1[u];
    for(int i=head[u];i;i=nxt[i]) d1[u]=max(d1[u],dfs(to[i]));
    return ++d1[u];

int main()
    n=read();m=read();
    FOR(i,1,m)
        int u=read(),v=read();
        add(u,v);add2(v,u);
        deg[v]++;
    
    MEM(d1,-1);
    FOR(i,1,n) if(d1[i]==-1) d1[i]=dfs(i);
    h=1;r=0;
    FOR(i,1,n) if(!deg[i]) q[++r]=i,seq[id[i]=++cnt]=i;
    while(h<=r)
        int u=q[h++];
        for(int i=head[u];i;i=nxt[i])
            int v=to[i];
            d2[v]=max(d2[v],d2[u]+1);
            if(!--deg[v]) q[++r]=v,seq[id[v]=++cnt]=v;
        
    
    FOR(i,1,n) fuck.insert(d1[i]);
    FOR(i,1,n)
        int u;
        if(i!=1)
            u=seq[i-1];
            for(int e=head[u];e;e=nxt[e])
                int v=to[e];
                fuck.insert(d2[u]+1+d1[v]);
            
            fuck.insert(d2[u]);
        
        u=seq[i];
        for(int e=head2[u];e;e=nxt2[e])
            int v=to2[e];
            multiset<int,greater<int> >::iterator it=fuck.find(d2[v]+1+d1[u]);
            fuck.erase(it);
        
        multiset<int,greater<int> >::iterator it=fuck.find(d1[u]);
        fuck.erase(it);
        if(*fuck.begin()<ans2) ans1=seq[i],ans2=*fuck.begin();
    
    printf("%d %d\n",ans1,ans2);

以上是关于[POI2014]RAJ(最短路,拓扑排序)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 3342 Legal or Not (最短路 拓扑排序?)

Luogu2149 [SDOI2009]Elaxia的路线-最短路+拓扑排序

图的最短路径和拓扑排序

NOIP2017 Day1 T3 逛公园(最短路+拓扑排序+DP)

每日算法图算法(遍历&MST&最短路径&拓扑排序)

BZOJ1880 SDOI2009 Elaxia的路线 最短路+拓扑排序