这道题打眼一看,好像是让求图中的差值最大的两个点a,b,但是好像又不大对,a,b两点必须是联通的,不进如此,a,b两点必须是v1到vn的一条路径上的点。
然后乱搞没搞出来,,无奈只能看题解,看完之后恍然大悟,原来只需两遍spfa(好像也有一遍做法),第一遍求出从vi的wm[i],就是从源节点1到vi的路径上最小的w[j],然后再反着遍历一遍(边也对应反过来,这里我用的是两个链表存储),从vn出发,把能访问到的点记录下来,最后O(n)的效率求max(w[i]-wm[i]),(pd[i]==1);
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int head1[500005],head2[500005],q[1000005],t1,t2,h,ans=0,i,u,n,m,x,y,z;
int w[100005],wm[100005];
bool pd[100005];
int read()
{
char c=getchar();int x=0;
while(c<48||c>57) c=getchar();
while(c>=48&&c<=57) x=x*10+c-48,c=getchar();
return x;
}
struct Edge
{
int next,from,to;
}e1[500005],e2[500005];
int add1(int from,int to)
{
e1[++t1].next=head1[from];
e1[t1].from=from;
e1[t1].to=to;
head1[from]=t1;
}
int add2(int from,int to)
{
e2[++t2].next=head2[from];
e2[t2].from=from;
e2[t2].to=to;
head2[from]=t2;
}
void spfa1()
{
int h=1,t=0;
q[1]=1;
wm[1]=w[1];
while(t<h)
{
t++;
u=q[t];
for(i=head1[u];i;i=e1[i].next)
if(wm[u]<wm[e1[i].to]||w[e1[i].to]<wm[e1[i].to])//很巧妙的简化了代码,因为每个点都必须访问一次
{
wm[e1[i].to]=min(wm[u],w[e1[i].to]);
if(!pd[e1[i].to])
q[++h]=e1[i].to;
pd[e1[i].to]=1;
}
pd[u]=0;
}
}
void spfa2()
{
memset(q,0,sizeof(q));
memset(pd,0,sizeof(pd));
int h=1,t=0;
q[1]=n;
pd[n]=1;//不要漏了
while(t<h)
{
t++;
u=q[t];
for(i=head2[u];i;i=e2[i].next)
{
if(!pd[e2[i].to])
{
q[++h]=e2[i].to;
pd[e2[i].to]=1;
}
}
}
}
int main()
{
// freopen("trade.in","r",stdin);
// freopen("trade.out","w",stdout);
n=read();m=read();
for(i=1;i<=n;i++)
{
w[i]=read();
wm[i]=w[i];
}
for(i=1;i<=m;i++)
{
x=read(),y=read(),z=read();
if(z==1)
add1(x,y),add2(y,x);
else add1(x,y),add1(y,x),add2(x,y),add2(y,x);
}
memset(wm,127/3,sizeof(wm));
spfa1();
spfa2();
for(i=1;i<=n;i++)
if(pd[i])
ans=max(ans,w[i]-wm[i]);
printf("%d",ans);
return 0;
}