[bzoj2125] 最短路

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

Solution

无脑建圆方树,大力出奇迹。

圆点和圆点的边权就直接是原图上的边权;

圆点和方点的边权设为圆点和这个环上\(dep\)最小的点的最短距离。

对于两个点\((x,y)\),设他们在圆方树上的\(lca\)\(t\),若\(t\)是圆点,就直接树上距离就好了。

否则, 少跳一步,先跳掉离方点最近的两个圆点,然后在原图上求环上最小距离就好了。

(萌新刚学OI,代码写的很丑,不要介意)

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

const int maxn = 2e5+10;

int n,m,q,cnt;
int head[maxn],tot=1,dfn[maxn],dfn_cnt,f[maxn],mark[maxn],fr[maxn],bel[maxn],dis[maxn];
struct edge{int to,nxt,w;}e[maxn<<1];

void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
void ins(int u,int v,int w) {add(u,v,w),add(v,u,w);}

int st[maxn],ed[maxn],val[maxn];

void dfs(int x,int fa) {
	dfn[x]=++dfn_cnt,f[x]=fa;
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].to!=fa) {
			if(!dfn[e[i].to])
				dis[e[i].to]=dis[x]+e[i].w,fr[e[i].to]=i,dfs(e[i].to,x);
			else if(dfn[e[i].to]<dfn[x]) {
				cnt++;int v=e[i].to;st[cnt]=e[i].to,ed[cnt]=x,val[cnt]=e[i].w;
				ins(v,cnt,0),mark[i]=mark[i^1]=1;
				int t=x;
				while(t!=v) {
					mark[fr[t]]=mark[fr[t]^1]=1;
					ins(t,cnt,min(dis[t]-dis[v],dis[x]-dis[t]+e[i].w));
					t=f[t];
				}
			}
		}
}

int w[maxn][20],dep[maxn],d[maxn];

void dfs2(int x,int fa) {
	w[x][0]=fa,dep[x]=dep[fa]+1;
	for(int i=1;i<=19;i++) w[x][i]=w[w[x][i-1]][i-1];
	for(int i=head[x];i;i=e[i].nxt)
		if(e[i].to!=fa&&!mark[i]) d[e[i].to]=d[x]+e[i].w,dfs2(e[i].to,x);
}

int lca(int x,int y) {
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=19;~i;i--) if(dep[w[x][i]]>=dep[y]) x=w[x][i];
	if(x==y) return x;
	for(int i=19;~i;i--) if(w[x][i]!=w[y][i]) x=w[x][i],y=w[y][i];
	return w[x][0];
}

int approach(int x,int t) {
	for(int i=19;~i;i--) if(dep[w[x][i]]>dep[t]) x=w[x][i];
	return x;
}

int main() {
	read(n),read(m),read(q);cnt=n;
	for(int i=1,x,y,z;i<=m;i++) read(x),read(y),read(z),ins(x,y,z);
	dfs(1,0),dfs2(1,0);
	for(int i=1;i<=q;i++) {
		int x,y;read(x),read(y);
		int t=lca(x,y);
		if(t<=n) {write(d[x]+d[y]-2*d[t]);continue;}
		int xx=approach(x,t),yy=approach(y,t);
		int ans=d[x]-d[xx]+d[y]-d[yy];
		if(dis[xx]<dis[yy]) swap(xx,yy);
		ans+=min(dis[xx]-dis[yy],dis[yy]-dis[st[t]]+dis[ed[t]]-dis[xx]+val[t]);
		write(ans);
	}
	return 0;
}
posted @ 2019-01-15 17:14  Hyscere  阅读(216)  评论(0编辑  收藏  举报