bzoj#2125. 最短路
题目描述
Description
给一个N个点M条边的连通无向图,满足每条边最多属于一个环,有Q组询问,每次询问两点之间的最短路径。
Input
输入的第一行包含三个整数,分别表示N和M和Q 下接M行,每行三个整数v,u,w表示一条无向边v-u,长度为w 最后Q行,每行两个整数v,u表示一组询问
Output
输出Q行,每行一个整数表示询问的答案
Solution
题意就是求仙人掌中两点最短路。
就是仙人掌圆方树的板子题。
对于每一个环用一个方点ttt代替环,从方点ttt向这个环的根节点xxx连一条代价为000的边,再从ttt向环上其他所有点yyy连一条代价为mindis(x,y)mindis(x,y)mindis(x,y)的边,并在ttt上记录整个环的总长度sumtsum_tsumt。
每一次询问(x,y)(x,y)(x,y)最短路时,分类讨论LCA(x,y)LCA(x,y)LCA(x,y)是方点还是圆点。
若是圆点答案即为dist(x,y)dist(x,y)dist(x,y)。
若是方点,则答案为xxx到环的最短路+yyy到环的最短路+xxx接入环的节点与yyy接入环的节点之间的最短路。
因此只要倍增或树剖预处理出LCA与路径和,每次跳LCA的时候顺路求解答案即可。
时间复杂度O(nlgn)O(n\lg n)O(nlgn)
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se secondusing namespace std;template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=1e9+7;
const int MAXN=30005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f;
}
struct enode{int to,c; };
vector<enode> e[MAXN],E[MAXN];
int DFN=0,n,m,Case,num,dist[MAXN],sum[MAXN],Fa[MAXN],flag[MAXN];
int dfn[MAXN],low[MAXN],fa[MAXN][15],sm[MAXN][15],dep[MAXN],Log[MAXN];
void add_edge(int x,int y,int c)
{
// cout<<"Edge:"<<x<<" "<<y<<" "<<c<<endl;E[x].PB(((enode){y,c}));E[y].PB(((enode){x,c}));
}
void solve(int x,int y,int c)
{sum[++num]=dist[y]-dist[x]+c;add_edge(x,num,0);for (int p=y;p!=x;p=Fa[p]){int Dis=min(dist[p]-dist[x],sum[num]-(dist[p]-dist[x]));add_edge(p,num,Dis);flag[p]=(Dis==(dist[p]-dist[x]));}
}
void tarjan(int x,int father)
{dfn[x]=low[x]=++DFN,Fa[x]=father;for (auto V:e[x]){int v=V.to,c=V.c;if (!dfn[v]) dist[v]=dist[x]+c,tarjan(v,x),upmin(low[x],low[v]);else if (v!=father) upmin(low[x],dfn[v]);if (dfn[x]<low[v]) add_edge(x,v,c);}for (auto V:e[x]){int v=V.to,c=V.c;if (Fa[v]!=x&&dfn[v]>dfn[x]) solve(x,v,c);}
}
void dfs(int x,int father)
{dep[x]=dep[father]+1;for (int i=1;i<=Log[dep[x]];i++) fa[x][i]=fa[fa[x][i-1]][i-1],sm[x][i]=sm[fa[x][i-1]][i-1]+sm[x][i-1];for (auto v:E[x]){if (v.to==father) continue;fa[v.to][0]=x;sm[v.to][0]=v.c;dfs(v.to,x);}
}
int getans(int x,int y)
{int s=0;if (dep[x]<dep[y]) swap(x,y);for (int i=Log[dep[x]];i>=0;i--)if (dep[fa[x][i]]>=dep[y]) s+=sm[x][i],x=fa[x][i];
// cout<<x<<" "<<y<<" "<<fa[x][0]<<" "<<s<<endl;if (x==y) return s;for (int i=Log[dep[x]];i>=0;i--)if (fa[x][i]!=fa[y][i]) s+=sm[x][i]+sm[y][i],x=fa[x][i],y=fa[y][i];// cout<<x<<" "<<y<<" "<<fa[x][0]<<" "<<s<<endl;if (fa[x][0]<=n) return s+sm[x][0]+sm[y][0];int Dis;if (flag[x]^flag[y]) Dis=sm[x][0]+sm[y][0];else Dis=abs(sm[x][0]-sm[y][0]);return s+min(Dis,sum[fa[x][0]]-Dis);
}
int main()
{n=read(),m=read(),Case=read(),num=n;for (int i=1;i<=m;i++){int u=read(),v=read(),c=read();e[u].PB(((enode){v,c}));e[v].PB(((enode){u,c}));}tarjan(1,0);dep[0]=-1,Log[1]=0;for (int i=2;i<=num;i++) Log[i]=Log[i>>1]+1;dfs(1,0);
// for (int i=1;i<=num;i++) cout<<fa[i][0]<<" "<<sm[i][0]<<" "<<fa[i][1]<<" "<<sm[i][1]<<endl;while (Case--){int x=read(),y=read();printf("%d\n",getans(x,y));}return 0;
}
/*
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 75
6
*/