[NOIp2009] 最优贸易

传送门:>Here<

给出一张有向图($n \leq 10^5, m \leq 5 \cdot 10^5$),每个点有两个点权——水晶买入价和水晶卖出价。一个商人从1走到n,点和边可以重复走,在某个点买进,在另一个店卖出。问其能赚到的最大差价。

解题思路

如果我们枚举买进点$i$,那么接下来就是要在$i \rightarrow n$中寻找卖出价的最大值。从各个点到一个固定点的路径问题,最适合采用`反向建边`。因此我们反向建边做一下。

而还要注意$i$必须是从1出发可达的(有向图存在连通性问题)。因此正向边也要做一下。

代码注意点

  SPFA做的是边权,而这里是点权。要注意转换。

$Code$

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int N = 100010;
const int INF = 715827882;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
    if(c == '-') w = -1, c = getchar();
    while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar();
    return x * w;
}
bool inQ[N];
int n,m,ans,x,y,z;
int a[N],maxx[N],minx[N];
vector <int> G[N];
vector <int> G2[N];
queue <int> q;
inline void AddEdge(int u, int v){
    G[u].push_back(v);
    G2[v].push_back(u);
}
inline void SPFA1(int s){
    memset(minx,0x3f,sizeof(minx));
    minx[s] = a[s];
    q.push(s);
    inQ[s] = 1;
    int cur,to,sz;
    while(!q.empty()){
        cur = q.front();
        q.pop();
        inQ[cur] = 0;
        sz = G[cur].size();
        for(int i = 0; i < sz; ++i){
            to = G[cur][i];
            if(minx[cur] < minx[to]){
                minx[to] = Min(minx[cur], a[to]);
                if(!inQ[to]){
                    q.push(to);
                    inQ[to] = 1;
                }
            }
        }
    }
}
inline void SPFA2(int s){
    memset(inQ,0,sizeof(inQ));
    while(!q.empty()) q.pop();
     maxx[s] = a[s];
    q.push(s);
    inQ[s] = 1;
    int cur,to,sz;
    while(!q.empty()){
        cur = q.front();
        q.pop();
        inQ[cur] = 0;
        sz = G2[cur].size();
        for(int i = 0; i < sz; ++i){
            to = G2[cur][i];
            if(maxx[cur] > maxx[to]){
                maxx[to] = Max(maxx[cur],a[to]);
                if(!inQ[to]){
                    q.push(to);
                    inQ[to] = 1;
                }
            }
        }
    }
}
int main(){
    //freopen(".in","r",stdin);
    n = r, m = r;
    for(int i = 1; i <= n; ++i) a[i] = r;
    for(int i = 1; i <= m; ++i){
        x = r, y = r, z = r;
        AddEdge(x,y);
        if(z == 2){
            AddEdge(y,x);
        }
    }
    SPFA1(1);
    SPFA2(n);
    for(int i = 1; i <= n; ++i){
        ans = Max(ans, maxx[i]-minx[i]);
    }
    printf("%d",ans);
    return 0;
}

 

posted @ 2018-07-08 11:59  DennyQi  阅读(143)  评论(0编辑  收藏  举报