版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}