因为这道题只能买卖一次,所以我们可以用dp的思想去分段,也就是以某个位置i作为分段点
从1-i能找到的最小值和从n-i能找到最大值,答案就是差值,因为两者没有约束。这样可以包含所有情况,虽然要重复。
问题是如何求去,因为本题有环,所以我们不能真的dp求,而dp其实就是dag的最x路,因此我们可以想到用最长路和最短路来求取
这种想法可以用spfa实现,不太适合用迪杰斯特拉,因为第一次出队不一定是最小的,这不是传统的最短路,只是想求取路上的最值
本题建反图来求取最大值,因为如果正着求,最大值不一定是正确的,因为有可能最大值这条路到不了终点,而我们必须要到终点
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<vector> #define x first #define y second using namespace std; typedef pair<int,int> pll; const int N=1e5+10; const int M=2e6+10; const int inf=0x3f3f3f3f; int hl[M],hr[M],ne[M],e[M],w[N],idx; int st[N]; int n,m; int dmin[N],dmax[N]; void add(int h[],int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void spfa(int h[],int dis[],int op){ queue<int> q; if(op==0){ memset(dis,0x3f,sizeof dmin); dis[1]=w[1]; q.push(1); } else{ memset(dis,-0x3f,sizeof dmax); dis[n]=w[n]; q.push(n); } while(q.size()){ int t=q.front(); q.pop(); int i; if(st[t]) st[t]=0; for(i=h[t];i!=-1;i=ne[i]){ int j=e[i]; if(op==0){ if(dis[j]>min(dis[t],w[j])){// w[j] is for the first time to update himself dis[j]=min(dis[t],w[j]); if(!st[j]){ q.push(j); st[j]=1; } } } else{ if(dis[j]<max(dis[t],w[j])){// w[j] is for the first time to update himself dis[j]=max(dis[t],w[j]); if(!st[j]){ q.push(j); st[j]=1; } } } } } } int main(){ cin>>n>>m; int i,j; memset(hl,-1,sizeof hl); memset(hr,-1,sizeof hr); for(i=1;i<=n;i++){ scanf("%d",&w[i]); } for(i=1;i<=m;i++){ int a,b; int op; scanf("%d%d%d",&a,&b,&op); add(hl,a,b),add(hr,b,a); if(op==2) add(hl,b,a),add(hr,a,b); } spfa(hl,dmin,0); spfa(hr,dmax,1); int ans=0; for(i=1;i<=n;i++){ ans=max(ans,dmax[i]-dmin[i]); } cout<<ans<<endl; }