【NOIP2009】最优贸易

题意

找一条路径上的点p,q,先经过点p,再经过点q,使q-p最大,求这个最大值。

1≤n≤1000001≤m≤500000

分析

其实图论模型和dp模型很类似,一个点到下一个点就是一个状态到下一个状态

我们考虑正反两次跑一下这个图,正着跑算出b[i]表示到当前点为止访问过的点的最小价值。

反向加边,算出s[i]表示到当前点为止访问过的点的最大价值。而这个只需要在松弛最短路的时候改一句话就行了。

最后的答案就是max{s[i]-b[i]}

MD写迪杰WA半天 向spfa屈服

代码

 

#include<bits/stdc++.h>
using namespace std;
#define N 200020
int n,m,cnt,cot,ans;
int w[N],b[N],s[N],vis[N],first[N],head[N];
struct email
{
    int u,v;
    int nxt;
}e[N*5],g[N*5];
queue<int>q;
inline void add1(int u,int v)
{
    e[++cnt].nxt=first[u];first[u]=cnt;
    e[cnt].u=u;e[cnt].v=v;
}
inline void add2(int u,int v)
{
    g[++cot].nxt=head[u];head[u]=cot;
    g[cot].u=u;g[cot].v=v;
}
void spfa()
{
    memset(b,0x3f,sizeof(b));
    b[1]=w[1];
    q.push(1);vis[1]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;    
        for(int i=first[u];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(b[v]>b[u])
            {
                b[v]=min(w[v],b[u]);
                if(!vis[v])q.push(v),vis[v]=1;
            }
            
        }
    }
    memset(vis,0,sizeof(vis));
    s[n]=w[n];
    q.push(n);vis[n]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();vis[u]=0;    
        for(int i=head[u];i;i=g[i].nxt)
        {
            int v=g[i].v;
            if(s[v]<s[u])
            {
                s[v]=max(w[v],s[u]);
                if(!vis[v])q.push(v),vis[v]=1;
            }
            
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    for(int i=1;i<=m;i++)
    {
        int u,v,c;
        scanf("%d%d%d",&u,&v,&c);
        if(c==1)add1(u,v),add2(v,u);
        else
        {
            add1(u,v);add1(v,u);
            add2(u,v);add2(v,u);
        }    
    }
    spfa();
    for(int i=1;i<=n;i++)ans=max(ans,s[i]-b[i]);
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2018-11-08 17:16  WJEMail  阅读(150)  评论(0编辑  收藏  举报