【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';
    }
}
posted @ 2019-04-02 11:45  Stargazer_cykoi  阅读(...)  评论(...编辑  收藏