大意
给定一棵无边权树,中间新穿插 m m m条有边权的边,问原树中所有边连向的两个点在失去此边后的最短路
思路
比较容易想到暴力
s
p
f
a
spfa
spfa
O
(
n
k
E
)
O(nkE)
O(nkE)
50分
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;int n,m,l[100001],x[100001],y[100001],w,dis[100001],tot,bh[100001][2];
bool vis[100001];
struct node{int next,to,w;}e[200001];
inline int read()
{
char c;int f=0,d=1;
while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void write(register int x){if(x>9)write(x/10);putchar(x%10+48);return;}
inline int spfa(register int x,register int y)
{
queue<int>q;
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[x]=0;q.push(x);vis[x]=true;
while(q.size())
{
int u=q.front();q.pop();vis[u]=true;
for(register int i=l[u];i;i=e[i].next)
{
int v=e[i].to,w=e[i].w;
if(dis[u]+w<dis[v])
{
dis[v]=dis[u]+w;
if(!vis[v]) vis[v]=true,q.push(v);
}
}
vis[u]=false;
}
return dis[y];
}
inline void add(register int u,register int v,register int w){e[++tot]=(node){l[u],v,w};l[u]=tot;return;}
signed main()
{
n=read();m=read();
for(register int i=1;i<n;i++)
{
x[i]=read();y[i]=read();
add(x[i],y[i],0);add(y[i],x[i],0);
bh[i][0]=tot-1;bh[i][1]=tot;
}
for(register int i=n,u,v;i<n+m;i++)
{
u=read();v=read();w=read();
add(u,v,w);add(v,u,w);
}
for(register int i=1,ans;i<n;i++)
{
e[bh[i][0]].w=e[bh[i][1]].w=0x3f3f3f3f;
ans=spfa(x[i],y[i]);
if(ans==0x3f3f3f3f){puts("-1");continue;}
write(ans);
putchar(10);
e[bh[i][0]].w=e[bh[i][1]].w=0;
}
}
然后我们发现,一棵树断开一条边后必定是两个联通分量,所以我们只需找到连接这两个联通分量的最短边即可,用并查集
O
(
n
m
α
(
n
)
)
O(nmα(n))
O(nmα(n))
70分
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;int l[100001],x[100001],y[100001];
int f[100001],u[100001],v[100001],w[100001],ans,n,m,fs[100001];
inline int find(register int x){return x==f[x]?x:f[x]=find(f[x]);}
inline int read()
{
char c;int f=0,d=1;
while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void write(register int x){if(x>9)write(x/10);putchar(x%10+48);return;}
signed main()
{
n=read();m=read();
for(register int i=1;i<n;i++)x[i]=read(),y[i]=read();
for(register int i=1;i<=m;i++) u[i]=read(),v[i]=read(),w[i]=read();
for(register int i=1,ans;i<n;i++)
{
ans=0x3f3f3f3f;
for(register int j=1;j<=n;j++) f[j]=j;
for(register int j=1;j<=n;j++)
if(i!=j) f[find(x[j])]=find(y[j]);
for(register int j=1;j<=m;j++)
if(find(u[j])!=find(v[j])) ans=min(ans,w[j]);
if(ans==0x3f3f3f3f) printf("-1");else
write(ans);putchar(10);
}
}
接着我们又发现,那条边其实就是之前点的
L
C
A
LCA
LCA,用
t
a
r
j
a
n
tarjan
tarjan算法即可
时间复杂度:
O
(
m
l
o
g
m
+
m
α
(
n
)
)
O(mlogm+mα(n))
O(mlogm+mα(n))
AC代码
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;int l[100010],dep[100010],p[100010];
int f[100010],ans,n,m,x,y,tot,fa[100010],d[100010];
bool vis[100010];
struct Node{int u,v,w;}e[100010];
struct node{int nxt,v,id;}E[200010];
inline void add(register int u,register int v,register int id){E[++tot]=(node){l[u],v,id};l[u]=tot;return;}
inline bool cmp(Node x,Node y){return x.w<y.w;}
inline int find(register int x){return !f[x]?x:f[x]=find(f[x]);}
inline int read()
{
char c;int f=0,d=1;
while(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),c>47&&c<58) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void write(register int x){if(x<0){x=-x;putchar('-');}if(x>9)write(x/10);putchar(x%10+48);return;}
inline void bfs(register int x)
{
queue<int>q;
q.push(x);
while(q.size())
{
int u=q.front();q.pop();vis[u]=true;
for(register int i=l[u];i;i=E[i].nxt)
{
int v=E[i].v;
if(!vis[v])
{
dep[v]=dep[u]+1;
fa[v]=u;
p[v]=E[i].id;
q.push(v);
}
}
}
return;
}
inline void merge(int &x,register int y){d[p[x]]=y;f[x]=find(fa[x]);x=f[x];return;}
signed main()
{
n=read();m=read();
for(register int i=1;i<n;i++) x=read(),y=read(),add(x,y,i),add(y,x,i),d[i]=-1;
for(register int i=1;i<=m;i++) e[i]=(Node){read(),read(),read()};
bfs(1);sort(e+1,e+1+m,cmp);
for(register int i=1;i<=m;i++)
{
int u=find(e[i].u),v=find(e[i].v);
while(u!=v) merge(dep[u]>dep[v]?u:v,e[i].w);
}
for(register int i=1;i<n;i++) write(d[i]),putchar(10);
}