您的位置:首页 > 其它

三点通信

2017-09-21 14:22 120 查看

题目描述



输入



输出



样例输入

5 5 3

1 2 20

1 3 20

1 4 20

3 5 15

4 5 15

2 3 4

3 4 5

5 4 4

5 4 3

1 2 20

1 3 20

1 4 20

3 5 15

2 3 4

3 4 5

5 4 4

样例输出

60

30

15

60

55

55

提示



solution

首先考虑一棵树的情况

对于x,y,z三个点

想到先求x,y到LCA(x,y)的距离,再加上LCA(x,y)到z的距离

可是,马上就会发现会有边重复计算。不过好像换y,z或x,z先算就可以了。所以,三种情况都算一下,求个min就可以了。

再来看看n=m的情况,是在一棵树上加了一条边,形成一个环。这是一个基环外向树。

以环上的每一个点为根,形成一些树

考虑三种情况,

1、若x,y,z在同一棵树上,就按照一棵树的情况做

2、若x,y,z有两个点在同一棵树上,另一点在另一棵树上,设x,y在同一棵树上,先求出x,y到LCA(x,y)的距离,再加上LCA(x,y)到root[x]的距离和z到root[z]的距离,最后还有root[x]到root[z]的最短距离(用前缀和处理一下)

3、若x,y,z都不在一棵树上,求出每一个点到根的距离,再加上三个根之间的最短距离

这样子就可以AC了

code:

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
bool is_bridge[200005];
int belong[100005],sum[1000000],vis[100005],id[100005],jh[100005],jhnum,fi,ti,dfn[100005],color[100005],low[100005],n,m,q,Next[200005],head[100005],vet[200005],w[200005],en,fa[100005][20],deep[100005],D[100005];
void addedge(int u,int v,long long val){
vet[++en]=v;
Next[en]=head[u];
head[u]=en;
w[en]=val;
}
void dfs(int u,int pre){
fa[u][0]=pre;
D[u]=D[pre]+1;
for(int i=1;i<=16;i++)
if(D[u]>=(1<<i))
fa[u][i]=fa[fa[u][i-1]][i-1];
else
break;
for(int i=head[u];i;i=Next[i]){
int v=vet[i];
if(v!=pre){
deep[v]=deep[u]+w[i];
dfs(v,u);
}
}
}
int lca(int x,int y){
if(D[x]<D[y])
swap(x,y);
int z=D[x]-D[y];
for(int i=0;i<=16;i++)
if(z&(1<<i))
x=fa[x][i];
for(int i=16;i>=0;i--)
if(fa[x][i]!=fa[y][i]){
x=fa[x][i];
y=fa[y][i];
}
if(x==y)
return x;
return fa[x][0];
}
void tarjan(int u,int pre){
dfn[u]=low[u]=++ti;
color[u]=1;
for(int i=head[u];i;i=Next[i]){
int v=vet[i];
if(!color[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else
if(v!=pre)
low[u]=min(low[u],dfn[v]);
if(low[v]>dfn[u]){
is_bridge[i]=true;
if(i&1)
is_bridge[i+1]=true;
else
is_bridge[i-1]=true;
}
}
}
void Dfs(int u){
jh[++jhnum]=u;
id[u]=jhnum;
vis[u]=1;
for(int i=head[u];i;i=Next[i])
if(!is_bridge[i]&&!vis[vet[i]])
Dfs(vet[i]);
}
void DFs(int u,int pre){
vis[u]++;
for(int i=head[u];i;i=Next[i])
if(!is_bridge[i]&&vis[vet[i]]<2&&vet[i]!=pre){
sum[id[vet[i]]+jhnum*vis[vet[i]]]=sum[id[u]+jhnum*(vis[u]-1)]+w[i];
DFs(vet[i],u);
}
}
void DFS(int u,int pre,int now){
belong[u]=now;
fa[u][0]=pre;
D[u]=D[pre]+1;
for(int i=1;i<=16;i++)
if(D[u]>=(1<<i))
fa[u][i]=fa[fa[u][i-1]][i-1];
else
break;
for(int i=head[u];i;i=Next[i]){
int v=vet[i];
if(v!=pre&&!id[v]){
deep[v]=deep[u]+w[i];
DFS(v,u,now);
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);
}
if(m<n){
D[1]=1;
dfs(1,0);
while(q--){
int x,y,z,ans,xx,yy;
scanf("%d%d%d",&x,&y,&z);
xx=lca(x,y);
yy=lca(xx,z);
ans=-deep[yy]*2-deep[xx]+deep[z]+deep[x]+deep[y];
xx=lca(x,z);
yy=lca(xx,y);
ans=min(ans,-deep[yy]*2-deep[xx]+deep[x]+deep[y]+deep[z]);
xx=lca(y,z);
yy=lca
caf1
(x,yy);
ans=min(ans,-deep[yy]*2-deep[xx]+deep[x]+deep[y]+deep[z]);
printf("%d\n",ans);
}
}
else{
tarjan(1,0);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=Next[j])
if(!is_bridge[j]){
fi=i;
goto ok;
}
ok:;
memset(vis,0,sizeof(vis));
Dfs(fi);
memset(vis,0,sizeof(vis));
DFs(fi,0);
for(int i=1;i<=jhnum;i++)
DFS(jh[i],0,i);
//printf("%d %d %d %d %d\n",sum[1],sum[2],sum[3],sum[4],sum[5]);
while(q--){
int x,y,z,ans=1000000000,xx,yy,zz,add;
scanf("%d%d%d",&x,&y,&z);
//printf("%d %d %d\n",belong[x],belong[y],belong[z]);
if(belong[x]==belong[y]&&belong[x]==belong[z]){
xx=lca(x,y);
yy=lca(xx,z);
ans=min(ans,-deep[yy]*2-deep[xx]+deep[x]+deep[y]+deep[z]);
xx=lca(x,z);
yy=lca(xx,y);
ans=min(ans,-deep[yy]*2-deep[xx]+deep[x]+deep[y]+deep[z]);
xx=lca(y,z);
yy=lca(x,yy);
ans=min(ans,-deep[yy]*2-deep[xx]+deep[x]+deep[y]+deep[z]);
}
else
if(belong[x]==belong[y]){
xx=lca(x,y);
ans=deep[x]+deep[y]-deep[xx]+deep[z];
xx=belong[x];
yy=belong[z];
if(xx>yy)
swap(xx,yy);
ans+=min(sum[yy]-sum[xx],sum[xx+jhnum]-sum[yy]);
}
else
if(belong[x]==belong[z]){
xx=lca(x,z);
ans=deep[x]+deep[y]-deep[xx]+deep[z];
xx=belong[x];
yy=belong[y];
if(xx>yy)
swap(xx,yy);
ans+=min(sum[yy]-sum[xx],sum[xx+jhnum]-sum[yy]);
}
else
if(belong[y]==belong[z]){
xx=lca(z,y);
ans=deep[x]+deep[y]-deep[xx]+deep[z];
xx=belong[x];
yy=belong[z];
if(xx>yy)
swap(xx,yy);
ans+=min(sum[yy]-sum[xx],sum[xx+jhnum]-sum[yy]);
}
else{
ans=deep[x]+deep[y]+deep[z];
xx=belong[x];
yy=belong[y];
zz=belong[z];
if(xx>yy)
swap(xx,yy);
if(yy>zz)
swap(yy,zz);
if(xx>yy)
swap(xx,yy);
add=sum[zz]-sum[xx];
add=min(add,sum[xx+jhnum]-sum[yy]);
add=min(add,sum[yy+jhnum]-sum[zz]);
ans+=add;
}
printf("%d\n",ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  LCA 基环外向树