原来的题解:https://blog.csdn.net/liufengwei1/article/details/84489935
这题有一步是要求1-n中间所有最短路边上的关键路径,也就是最短路边组成的子图的桥
当时训练赛我还不会求桥,就去网上找有向图求桥的代码
然后WA了半天。。。后来发现别人都是先转换成无向图再求桥的
这里更新为了lyd《算法竞赛进阶指南》上求桥的板子
如果搜索树上某个点u的子节点v,dfn[u]<low[v]。那么u-v这条边是割边。
理性分析一下,这样说明v无法通过一条路径到达u本身和之前访问到的点,那么u,v这条边一旦断开,那么v和u就将不连通
注意重边的情况,我们再前向星数组中存双向边是(2,3)(4,5)一对一对的,那么在更新low的时候,要判断上一条到达u点的边是否跟当前枚举的边在本质上是一条边,如果是,那么就不能用来更新low。
#include<bits/stdc++.h>
#define maxl 100010
using namespace std;
int n,m,cnt1,cnt2,cnt3,ind;
int ehead1[maxl],ehead2[maxl],ehead3[maxl];
int dfn[maxl],low[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 in_edge)
{
int v;
bool flag=0;
dfn[u]=low[u]=++ind;
for(int i=ehead3[u];i;i=e3[i].nxt)
{
v=e3[i].to;
if(!dfn[v])
{
tarjan(v,i);
low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])
cut[e3[i].id]=cut[e3[i^1].id]=true;
}
else if(i!=(in_edge^1))
low[u]=min(low[u],dfn[v]);
}
}
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=1;
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;
memset(dfn,0,sizeof(int)*(n+1));
memset(low,0,sizeof(int)*(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;
}