题意:给出一张有向图,每条边有长度,对于每条边,你要回答将该边的方向取反后,从起点到终点的最短距离是增加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 }