三点通信

来源:互联网 发布:上汽集团 知乎 编辑:程序博客网 时间:2024/05/21 17:00

题目描述

这里写图片描述

输入

这里写图片描述

输出

这里写图片描述

样例输入

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(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;}
原创粉丝点击