算法竞赛进阶指南 图论 最短路
题意:一张图,由单向边和双向边组成,每个节点有固定的权值,求从1走到n的最大权值之差
(不知道为啥放最短路里,明明一个bfs就可以解决了
存边时除了单向双向边要注意,还要存一张反边图
bfs一遍记录从1到n每个节点到1的最小权值
再bfs一遍跑反边图,记录从n到1每个节点到n的最大权值
最后遍历一遍统计最大差值就ok了
#include<algorithm> #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<string> #include<map> #include<queue> #include<stack> #include<list> #include<set> using namespace std; typedef long long ll; typedef pair<ll,ll> P; typedef long double ld; #define mem(x) memset(x, 0, sizeof(x)) #define me(x) memset(x, -1, sizeof(x)) #define fi first #define se second #define fo(i,n) for(i=0; i<n; i++) #define sc(x) scanf("%I64d", &x) #define sca(n,m) scanf("%I64d%I64d", &n, &m) #define pr(x) printf("%I64d\n", x) #define pri(x) printf("%I64d ", x) #define lowbit(x) x&-x const ll MOD = 1e9 + 7; const ll oo = 1e18; const ll N = 4e5 + 5; struct node { ll nxt, to; }e[N], e1[N]; ll head[N], cnt, vis[N], mi[N], a[N], vi[N], mx[N]; ll head1[N], cnt1; void add(ll u, ll v) { e[cnt].to=v; e[cnt].nxt=head[u]; head[u]=cnt++; } void add1(ll u, ll v) { e1[cnt1].nxt=head1[u]; e1[cnt1].to=v; head1[u]=cnt1++; } void bfs(ll n) { queue<ll> q; q.push(1); vis[1]=1; mi[1]=min(mi[1], a[1]); while(q.size()) { ll u=q.front(); q.pop(); for(ll i=head[u]; ~i; i=e[i].nxt) { ll v=e[i].to; mi[v]=min(min(mi[v],a[v]), mi[u]); if(!vis[v]) { vis[v]=1; q.push(v); } } } q.push(n); vi[n]=1; mx[n]=max(mx[n], a[n]); while(q.size()) { ll u=q.front(); q.pop(); for(ll i=head1[u]; ~i; i=e1[i].nxt) { ll v=e1[i].to; mx[v]=max(max(mx[v],a[v]), mx[u]); if(!vi[v]) { vi[v]=1; q.push(v); } } } } int main() { ll i, j, k; ll n, m; ll u, v; cin>>n>>m; for(i=1; i<=n; i++) cin>>a[i], mi[i]=oo, head[i]=-1, mx[i]=-oo, head1[i]=-1; while(m--) { cin>>u>>v>>k; if(k==1) add(u,v), add1(v,u); else add(u,v), add(v,u), add1(u,v), add1(v,u); } bfs(n); ll ans=0; for(i=1; i<=n; i++) //cout<<mi[i]<<" "<<mx[i]<<endl; { if(mi[i]!=oo && mx[i]!=-oo && mx[i]>mi[i]) ans=max(mx[i]-mi[i], ans); } cout<<ans<<endl; return 0; }