【BZOJ2125】—最短路(圆方树+树链剖分)
题意:询问仙人掌上2点之间最短路
先建出圆方树,每个圆点到方点的距离为到这个环最高点的最短距离
每次询问分类讨论一下圆点方点
如果是方点的话找到到这个环的那个入点,计算2个入点之间最短距离就可以了
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<18|1;
#define file freopen("lx.cpp","r",stdin);
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=gc();
int res=0,f=0;
while(!isdigit(ch))f^=(ch=='-'),ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?-res:res;
}
const int N=40004;
struct Graph{
int cnt,adj[N],nxt[N<<1],to[N<<1],val[N<<1];
inline void add(int u,int v,int w){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
}
inline void addedge(int u,int v,int w){
add(u,v,w),add(v,u,w);
}
}G,T;
int n,m,q;
int dfn[N],fa[N],dep[N],bel,plc[N],dis[N],low[N],stk[N],tot,len[N];
inline void buildRec(int u,int v,int w){
int top=dep[v]-dep[u]+1,sum=w,dt=0;
for(int i=v;i!=u;i=fa[i])stk[top--]=i,sum+=dis[i]-dis[fa[i]];
bel++,len[bel]=sum,stk[1]=u;
for(int i=1;i<=dep[v]-dep[u]+1;i++){
int d=min(dt,sum-dt);
T.addedge(bel,stk[i],d);
plc[stk[i]]=d==dt;
dt+=dis[stk[i+1]]-dis[stk[i]];
}
}
void tarjan(int u){
dfn[u]=low[u]=++tot;
for(int e=G.adj[u];e;e=G.nxt[e]){
int v=G.to[e];
if(v==fa[u])continue;
if(!dfn[v]){
fa[v]=u,dep[v]=dep[u]+1,dis[v]=dis[u]+G.val[e];
tarjan(v),low[u]=min(low[u],low[v]);
}
else low[u]=min(low[u],dfn[v]);
if(dfn[u]<low[v])T.addedge(u,v,G.val[e]);
}
for(int e=G.adj[u];e;e=G.nxt[e]){
int v=G.to[e];
if(v==fa[u])continue;
if(fa[v]!=u&&dfn[u]<dfn[v])buildRec(u,v,G.val[e]);
}
}
namespace SLPF{
int pos[N],idx[N],siz[N],son[N],dis[N],fa[N],top[N],dep[N],tot;
void dfs1(int u){
siz[u]=1;
for(int e=T.adj[u];e;e=T.nxt[e]){
int v=T.to[e];
if(v==fa[u])continue;
dep[v]=dep[u]+1,fa[v]=u,dis[v]=dis[u]+T.val[e];
dfs1(v),siz[u]+=siz[v];
if(siz[u]>siz[son[u]])son[u]=v;
}
}
void dfs2(int u,int tp){
pos[u]=++tot,idx[tot]=u,top[u]=tp;
if(son[u])dfs2(son[u],tp);
for(int e=T.adj[u];e;e=T.nxt[e]){
int v=T.to[e];
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
inline int Lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]])swap(u,v);
u=fa[top[u]];
}return dep[u]>dep[v]?v:u;
}
inline int jump(int u,int g){
int pre;
while(top[u]!=top[g]){
pre=top[u],u=fa[top[u]];
}
return u==g?pre:idx[pos[g]+1];
}
inline int query(int u,int v){
int lca=Lca(u,v);
if(lca<=n)return dis[u]+dis[v]-2*dis[lca];
int sonu=jump(u,lca),sonv=jump(v,lca);
int du=dis[sonu]-dis[lca],dv=dis[sonv]-dis[lca];
if(plc[sonu])du=len[lca]-du;if(plc[sonv])dv=len[lca]-dv;
if(du<dv)swap(du,dv);
return min(du-dv,len[lca]-du+dv)+dis[u]-dis[sonu]+dis[v]-dis[sonv];
}
}
int main(){
//file;
bel=n=read(),m=read(),q=read();
for(int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
G.addedge(u,v,w);
}
tarjan(1);
SLPF::dfs1(1),SLPF::dfs2(1,1);
while(q--){
int u=read(),v=read();
cout<<SLPF::query(u,v)<<'\n';
}
}