题意:给出一张有向图,每条边有长度,对于每条边,你要回答将该边的方向取反后,从起点到终点的最短距离是增加or减小or不变。

首先求出起点到所有点的最短距离和所有点到终点的最短距离(两次DIjkstra,第二次跑反向边即可),并建出最短路图。设ds[u]为起点到点u的最短距离,dt[u]为点u到终点的最短距离,对于每条边,设该边的两个端点u->v,以及边权c,分情况讨论:

若ds[v]+c+dt[u]>dt[s],此时将边取反后最短距离减小,否则需要判断该边是否为最短路图上s到t的割边,若是则最短距离增加,否则不变。

如何判断该边是否为s到t的割边?其实方法很简单,如果是割边,那么从s到t的所有路径都经过该边。由于最短路图是个DAG,设in[u]表示从起点走到u的路径数,out[v]表示从v走到终点的路径数,则每条边被通过的路径数=in[u]*out[v],只需判断in[u]*out[v]是否等于out[s]即可。注意这个路径数可能会很大甚至存不下,但由于只需要判断是否相等用哈希就可以,可以用unsigned long long溢出自动取模。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef unsigned long long ll;
 4 const int N=1e5+10,inf=0x3f3f3f3f;
 5 int n,m,hd[N],ne;
 6 ll in[N],out[N],ds[N],dt[N],vis[N];
 7 struct E {int u,v,c,nxt;} e[N<<1];
 8 void addedge(int u,int v,int c) {e[ne]= {u,v,c,hd[u]},hd[u]=ne++;}
 9 struct D {
10     int u;
11     ll g;
12     bool operator<(const D& b)const {return g>b.g;}
13 };
14 priority_queue<D> q;
15 void upd(int u,ll ad,ll* dp) {
16     if(dp[u]>ad)dp[u]=ad,q.push({u,ad});
17 }
18 void dij() {
19     memset(ds,inf,sizeof ds);
20     while(q.size())q.pop();
21     upd(1,0,ds);
22     while(q.size()) {
23         int u=q.top().u;
24         ll g=q.top().g;
25         q.pop();
26         if(ds[u]!=g)continue;
27         for(int i=hd[u]; ~i; i=e[i].nxt)if(!(i&1))upd(e[i].v,g+e[i].c,ds);
28     }
29     memset(dt,inf,sizeof dt);
30     while(q.size())q.pop();
31     upd(2,0,dt);
32     while(q.size()) {
33         int u=q.top().u;
34         ll g=q.top().g;
35         q.pop();
36         if(dt[u]!=g)continue;
37         for(int i=hd[u]; ~i; i=e[i].nxt)if(i&1)upd(e[i].v,g+e[i].c,dt);
38     }
39 }
40 ll dfsin(int u) {
41     ll& ret=in[u];
42     if(vis[u])return ret;
43     vis[u]=1,ret=0;
44     if(u==1)return ret=1;
45     for(int i=hd[u]; ~i; i=e[i].nxt)if(i&1) {
46             int v=e[i].v;
47             if(dt[u]+e[i].c!=dt[v])continue;
48             ret+=dfsin(v);
49         }
50     return ret;
51 }
52 ll dfsout(int u) {
53     ll& ret=out[u];
54     if(vis[u])return ret;
55     vis[u]=1,ret=0;
56     if(u==2)return ret=1;
57     for(int i=hd[u]; ~i; i=e[i].nxt)if(!(i&1)) {
58             int v=e[i].v;
59             if(ds[u]+e[i].c!=ds[v])continue;
60             ret+=dfsout(v);
61         }
62     return ret;
63 }
64 int main() {
65     memset(hd,-1,sizeof hd),ne=0;
66     scanf("%d%d",&n,&m);
67     while(m--) {
68         int u,v,c;
69         scanf("%d%d%d",&u,&v,&c);
70         addedge(u,v,c);
71         addedge(v,u,c);
72     }
73     dij();
74     memset(vis,0,sizeof vis);
75     for(int i=1; i<=n; ++i)dfsin(i);
76     memset(vis,0,sizeof vis);
77     for(int i=1; i<=n; ++i)dfsout(i);
78     for(int i=0; i<ne; i+=2) {
79         int u=e[i].u,v=e[i].v;
80         if(dt[1]>ds[v]+e[i].c+dt[u])puts("HAPPY");
81         else if(ds[u]+e[i].c==ds[v]&&in[u]*out[v]==out[1])puts("SAD");
82         else puts("SOSO");
83     }
84     return 0;
85 }
01-15 01:03