[Gym-101986F] [Problem F] 2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest
阿新 • • 發佈:2018-11-25
先把1到2的最短路上的邊全部標記上,標記一條邊是否屬於最短路,就是正著跑一遍最短路得到dis1,倒著跑一遍得到dis2,如果對於一條邊u,v,c,dis1[u]+c+dis2[v]=dis1[2]那麼就是最短路上的邊了。
對於最短路上的邊,翻轉他,如果他是橋,那麼最短路一定會變長,如果不是,說明還有不經過這條邊的最短路,那麼最短路是不變的。
對於不是最短路上的邊,如果dis1[v]+c+dis2[u]<dis1[2]那麼最短路就變小了,如果>=,那麼說明經過這條反向邊的最短路並沒有比原來真正的最短路更短,那麼最短路就是不變的。
求橋的方法,網上百度了一個有向圖求橋,WA了半天,後來看別人有向圖求橋都是先變成無向圖,然後tarjan求橋。
求橋還可以利用橋的性質求,從1拓撲排序得到u點的路徑數,num1[u],從2倒著拓撲排序得到到v點的路徑數num2[v],如果num1[u]*num2[v]=num1[2]也就是從1到2的所有路徑總數,那麼u-v這條邊也是最短路中的橋。
#include<bits/stdc++.h> #define maxl 100010 using namespace std; int n,m,cnt1,cnt2,cnt3,ind,top,ff; int ehead1[maxl],ehead2[maxl],ehead3[maxl]; int dfn[maxl],low[maxl],s[maxl],f[maxl]; long long dis1[maxl],dis2[maxl]; struct edge { int x,y,l; }edg[maxl]; struct ed { int to,nxt,l,id; }e1[maxl<<1],e2[maxl<<1],e3[maxl<<1]; typedef pair <long long,int> p; priority_queue<p,vector<p>,greater<p> > q; bool in[maxl],edin[maxl],cut[maxl]; typedef pair <int,int> pp; typedef pair <pp,int> ppp; map <ppp,int> mp; inline void add1(int u,int v,int l,int id) { ++cnt1;e1[cnt1].to=v;e1[cnt1].nxt=ehead1[u]; e1[cnt1].l=l;e1[cnt1].id=id;ehead1[u]=cnt1; } inline void add2(int u,int v,int l,int id) { ++cnt2;e2[cnt2].to=v;e2[cnt2].nxt=ehead2[u]; e2[cnt2].l=l;e2[cnt2].id=id;ehead2[u]=cnt2; } inline void add3(int u,int v,int l,int id) { ++cnt3;e3[cnt3].to=v;e3[cnt3].nxt=ehead3[u]; e3[cnt3].l=l;e3[cnt3].id=id;ehead3[u]=cnt3; } inline void prework() { scanf("%d%d",&n,&m); memset(ehead1,0,sizeof(int)*(n+1)); memset(ehead2,0,sizeof(int)*(n+1)); memset(ehead3,0,sizeof(int)*(n+1)); int x,y,l; cnt1=0;cnt2=0;mp.clear(); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&l); edg[i].x=x;edg[i].y=y;edg[i].l=l; edin[i]=false;cut[i]=false; add1(x,y,l,i);add2(y,x,l,i); mp[make_pair(make_pair(x,y),l)]+=1; } } inline void tarjan(int u,int fa) { int v; bool flag=0; dfn[u]=low[u]=++ind;s[++top]=u;in[u]=true; for(int i=ehead3[u];i;i=e3[i].nxt) { v=e3[i].to; if(v==fa&& !flag){ flag=1; continue; } if(!dfn[v]) { tarjan(v,u); low[u]=min(low[u],low[v]); if(low[v]>dfn[u]) cut[e3[i].id]=true; } else if(in[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]) { ff++; do { v=s[top];s[top--]=0; f[v]=ff; in[v]=false; }while(v!=u); } } inline void mainwork() { while(!q.empty()) q.pop(); int u,v;p d; for(int i=1;i<=n;i++) dis1[i]=dis2[i]=1ll<<60; memset(in,false,sizeof(bool)*(n+1)); dis1[1]=0;q.push(make_pair(0ll,1)); while(!q.empty()) { do { d=q.top();q.pop(); u=d.second; }while((d.first>dis1[u] || in[u]) && !q.empty()); in[u]=true; for(int i=ehead1[u];i;i=e1[i].nxt) { v=e1[i].to; if(dis1[v]>dis1[u]+e1[i].l) { dis1[v]=dis1[u]+e1[i].l; q.push(make_pair(dis1[v],v)); } } } while(!q.empty()) q.pop(); memset(in,false,sizeof(bool)*(n+1)); dis2[2]=0;q.push(make_pair(0ll,2)); while(!q.empty()) { do { d=q.top();q.pop(); u=d.second; }while((d.first>dis2[u] || in[u]) && !q.empty()); in[u]=true; for(int i=ehead2[u];i;i=e2[i].nxt) { v=e2[i].to; if(dis2[v]>dis2[u]+e2[i].l) { dis2[v]=dis2[u]+e2[i].l; q.push(make_pair(dis2[v],v)); } } } cnt3=0; for(int i=1;i<=m;i++) { u=edg[i].x;v=edg[i].y; if(dis1[u]+dis2[v]+edg[i].l==dis1[2]) { edin[i]=true; add3(u,v,edg[i].l,i); add3(v,u,edg[i].l,i); } } ind=0;top=0;ff=0; memset(dfn,0,sizeof(int)*(n+1)); memset(low,0,sizeof(int)*(n+1)); memset(in,false,sizeof(bool)*(n+1)); tarjan(1,0); } inline void print() { int x,y; for(int i=1;i<=m;i++) { if(edin[i]) { if(cut[i] && mp[make_pair(make_pair(edg[i].x,edg[i].y),edg[i].l)]==1) puts("SAD"); else puts("SOSO"); } else { x=edg[i].x;y=edg[i].y; if(dis1[y]+edg[i].l+dis2[x]<dis1[2]) puts("HAPPY"); else puts("SOSO"); } } } int main() { prework(); mainwork(); print(); return 0; }