看完这一题,应该可以很容易地想到,要使得差值最大,就要找到1到n的全部路径上,最大值与最小值差值最大的那条路径,并且要保证最小值在最大值的前面,那么可以跑两次spfa,找出1到每个点路径上的最小值,再找到每个点到n的路径上的最大值,最后枚举每一条边(是边不是路径!)的起点和终点,计算出终点到n的路径上的最大值,减去1到起点的路径上的最小值,然后用ans记录这些差值中最大的那个就好了。
代码:
#include <cstdio>
#include <cstring>
int dis[2][1000010];
int n,m,a[1000010],len=0;
struct node{int x,y,next;};
node e[1000010];
int first[1000010];
void buildroad(int x,int y)//邻接表
{
len++;
e[len].x=x;
e[len].y=y;
e[len].next=first[x];
first[x]=len;
}
int road[500010][3];
int q[1000010],st,ed;
bool v[1000010];
int maxx(int x,int y){return x>y?x:y;}
int minn(int x,int y){return x<y?x:y;}
void spfamin()
{
st=1,ed=2;
q[st]=1;
v[1]=true;
dis[0][1]=a[1];
while(st!=ed)
{
int x=q[st];
for(int i=first[x];i;i=e[i].next)
{
int y=e[i].y;
if(dis[0][y]>minn(a[y],dis[0][x]))
{
dis[0][y]=minn(a[y],dis[0][x]);
if(!v[y])
{
q[ed++]=y;
if(ed>n)ed=1;
v[y]=true;
}
}
}
v[x]=false;
st++;
if(st>n)st=1;
}
}
void spfamax()
{
st=1,ed=2;
q[st]=n;
v[1]=true;
dis[1][n]=a[n];
while(st!=ed)
{
int x=q[st];
for(int i=first[x];i;i=e[i].next)
{
int y=e[i].y;
if(dis[1][y]<maxx(a[y],dis[1][x]))
{
dis[1][y]=maxx(a[y],dis[1][x]);
if(!v[y])
{
q[ed++]=y;
if(ed>n)ed=1;
v[y]=true;
}
}
}
v[x]=false;
st++;
if(st>n)st=1;
}
}
void work(int id)//跑两次spfa,一次正向跑,一次反向跑
{
memset(first,0,sizeof(first));len=0;
for(int i=1;i<=m;i++)
{
if(road[i][2]-1)buildroad(road[i][1],road[i][0]),buildroad(road[i][0],road[i][1]);//双向边直接建
else if(id)buildroad(road[i][1],road[i][0]);
else buildroad(road[i][0],road[i][1]);
}
if(id)spfamax();else spfamin();
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),dis[0][i]=999999999,dis[1][i]=0;
for(int i=1;i<=m;i++)
scanf("%d %d %d",&road[i][0],&road[i][1],&road[i][2]);
memset(v,false,sizeof(v));
work(1);work(0);
int ans=0;
for(int i=1;i<=len;i++)
{
int x=e[i].x,y=e[i].y;
if(dis[0][x]!=999999999&&dis[1][y]!=0&&dis[1][y]-dis[0][x]>ans)ans=dis[1][y]-dis[0][x];//枚举每一条边,用差值更新aans
}
printf("%d",ans);
}