[bzoj2125][圆方树]最短路

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/82386228

Description

给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。

Input

输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w
最后Q行,每行两个整数v,u表示一组询问

Output

输出Q行,每行一个整数表示询问的答案

Sample Input

9 10 2

1 2 1

1 4 1

3 4 1

2 3 1

3 7 1

7 8 2

7 9 2

1 5 3

1 6 4

5 6 1

1 9

5 7

Sample Output

5

6

HINT

对于100%的数据,N<=10000,Q<=10000

题解

又做个裸题爽一爽….
这次要把圆方树建出来
圆点到圆点的边权即为原边权
圆点到方点的边权即为这个圆点到方点的父亲的最短路长度
考虑如何计算答案
先对要求的两个点求LCA
如果LCA是圆点,直接输出答案
如果是方点,我们发现最后路径是在一个环上
设求的是(x,y)的答案,我们把(x,y)移到(u,v),保证u,v均是圆点且是LCA的孩子节点
再暴力计算u,v的环上最短路即可

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
struct node{int x,y,c,d,next;}a[210000],e[210000];int len1,last1[210000],len2,last2[210000];
void ins_a(int x,int y,int c){len1++;a[len1].x=x;a[len1].y=y;a[len1].c=c;a[len1].next=last1[x];last1[x]=len1;}
void ins_b(int x,int y,int c,int d){len2++;e[len2].x=x;e[len2].y=y;e[len2].c=c;e[len2].d=d;e[len2].next=last2[x];last2[x]=len2;}
int low[210000],dfn[210000],sta[210000],r[210000],id,cnt,tp1;
int belong[210000],d[210000],gg[210000],hh[210000],po[210000],go[210000],root,tp2;
void link()
{
    int sum=0;
    for(int i=1;i<=d[0];i++)
    {
        sum+=d[i];
        if(i!=1)d[i]+=d[i-1];
    }
    hh[cnt]=sum;
    ins_b(cnt,r[1],0,0);ins_b(r[1],cnt,0,0);
    for(int i=2;i<=r[0];i++)
    {
        int mn=min(d[i-1],sum-(d[i-1]));
        ins_b(cnt,r[i],mn,d[i-1]);ins_b(r[i],cnt,mn,d[i-1]);
    }
/*  puts("checker:::::");
    for(int i=1;i<=r[0];i++)printf("%d %d\n",r[i],d[i]);
    printf("%d\n",sum);*/
}
bool v[210000];
void tarjan(int x,int fa)
{
    bool bk=false;
    low[x]=dfn[x]=++id;sta[++tp1]=x;v[x]=true;
    for(int k=last1[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(dfn[y]==-1)
        {
            gg[++tp2]=a[k].c;
            tarjan(y,x);low[x]=min(low[x],low[y]);
            if(low[y]>dfn[x])tp1--,tp2--,ins_b(x,y,a[k].c,0),ins_b(y,x,a[k].c,0);
            else if(low[y]==dfn[x])
            {
                cnt++;
                r[r[0]=1]=x;d[d[0]=1]=gg[tp2--];
                int i;
                do
                {
                    i=sta[tp1--];v[i]=false;
                    r[++r[0]]=i;d[++d[0]]=gg[tp2--];
                    belong[i]=cnt;
                }while(i!=y);
                link();
            }
        }
        else 
        {
            if(y!=fa&&v[y])gg[++tp2]=a[k].c;
            else if(y==fa&&v[y]&&bk)gg[++tp2]=a[k].c;
            if(y!=fa)low[x]=min(low[x],dfn[y]);
            else if(!bk)bk=true;
            else low[x]=min(low[x],dfn[y]);
        }
    }
}
int bin[25],fa[210000][25],s[210000][25],num[210000],dep[210000];
void pre_tree_node(int x)
{
    for(int i=1;bin[i]<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1],s[x][i]=s[x][i-1]+s[fa[x][i-1]][i-1];
    for(int k=last2[x];k;k=e[k].next)
    {
        int y=e[k].y;
        if(y!=fa[x][0])
        {
            fa[y][0]=x;dep[y]=dep[x]+1;s[y][0]=e[k].c;num[y]=e[k].d;
            pre_tree_node(y);
        }
    }
}
int tmp;
int lca(int x,int y)
{
    if(dep[x]<dep[y])swap(x,y);tmp=0;
    for(int i=20;i>=0;i--)if(bin[i]<=dep[x] && dep[fa[x][i]]>=dep[y])tmp+=s[x][i],x=fa[x][i];
    if(x==y)return x;
    for(int i=20;i>=0;i--)if(bin[i]<=dep[x] && fa[x][i]!=fa[y][i])tmp+=s[x][i]+s[y][i],x=fa[x][i],y=fa[y][i];
    tmp+=s[x][0]+s[y][0];
    return fa[x][0];
}
int up(int x,int p)
{
    for(int i=20;i>=0;i--)if(bin[i]<=p)x=fa[x][i],p-=bin[i];
    return x;
}
int n,m,Q;
int main()
{
//  freopen("input","r",stdin);
    //freopen("a.out","w",stdout);
    bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
    scanf("%d%d%d",&n,&m,&Q);
    for(int i=1;i<=m;i++)
    {
        int x,y,c;scanf("%d%d%d",&x,&y,&c);
        ins_a(x,y,c);ins_a(y,x,c);
    }
    memset(v,false,sizeof(v));
    memset(dfn,-1,sizeof(dfn));cnt=n;
    for(int i=1;i<=n;i++)if(dfn[i]==-1)
    {
        root=i;tarjan(i,0);
        pre_tree_node(i);
    }
//  for(int i=1;i<=len2;i++)printf("CHECKER: %d %d %d %d\n",e[i].x,e[i].y,e[i].c,e[i].d);
    while(Q--)
    {
        int x,y;scanf("%d%d",&x,&y);
        int LA=lca(x,y);
        if(LA<=n)printf("%d\n",tmp);
        else
        {
            int g1=dep[x]-dep[LA]-1,g2=dep[y]-dep[LA]-1;
            int u=up(x,g1),v=up(y,g2);
            int pos=belong[u];
            tmp-=s[u][0]+s[v][0];
            tmp+=min(abs(num[u]-num[v]),hh[pos]-abs(num[u]-num[v]));
            printf("%d\n",tmp);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/82386228