[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

HINT
对于100%的数据,N<=10000,Q<=10000


这题写的我真TM舒服……

首先对仙人掌建出一棵圆方树,考虑树上的边权,如果是圆点连圆点,则边权不变;如果是圆点连方点,则边权为圆点到方点所属环上,dfs序最小的点的距离

然后我们考虑lca的两种情况,如果lca是圆点,那么我们直接输出圆方树上的两点之间距离;如果lca是方点,我们找到\(x,y\)在lca儿子中的祖先节点\(x',y'\),则答案为\(dis_{x\rightarrow x'}+dis_{x'\rightarrow y'}+dis_{y'\rightarrow y}\)

(树剖求lca找\(x',y'\)时细节贼难受……)

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Fi first
#define Se second
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef pair<int,int>pii;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1; char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1; char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=1e4;
int V[N+10],cnt,n,m,q;
struct node{
    int lca,x,y;
    node(){lca=x=y=0;}
    node(int _l,int _x,int _y){lca=_l,x=_x,y=_y;}
    void insert(int _l,int _x,int _y){lca=_l,x=_x,y=_x;}
};
struct S1{  
    int pre[(N<<2)+10],now[(N<<1)+10],child[(N<<2)+10],val[(N<<2)+10],tot;
    int fa[(N<<1)+10],deep[(N<<1)+10],top[(N<<1)+10],Rem[(N<<1)+10],size[(N<<1)+10],dis[(N<<1)+10];
    void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
    void dfs(int x){
        deep[x]=deep[fa[x]]+1,size[x]=1;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]) continue;
            fa[son]=x,dis[son]=dis[x]+val[p];
            dfs(son),size[x]+=size[son];
            if (size[Rem[x]]<size[son]) Rem[x]=son;
        }
    }
    void build(int x){
        if (!x) return;
        top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
        build(Rem[x]);
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]||son==Rem[x])    continue;
            build(son);
        }
    }
    node LCA(int x,int y){
        int lastx=0,lasty=0;
        while (top[x]!=top[y]){
            if (deep[top[x]]<deep[top[y]])  lasty=top[y],y=fa[top[y]];
            else    lastx=top[x],x=fa[top[x]];
        }
        if (x==y)   return node(x,lastx,lasty);
        if (deep[x]<deep[y])    return node(x,lastx,Rem[x]);
        else    return node(y,Rem[y],lasty);
        //WA了好几次,画了图才发现应该这样写……
    }
}RST;//Round Square Tree
struct S2{
    int pre[(N<<2)+10],now[N+10],child[(N<<2)+10],val[(N<<2)+10];
    int fa[N+10],dfn[N+10],low[N+10],fv[N+10],dis[N+10],stack[N+10],belong[N+10];
    bool instack[N+10];
    int tot,Time,top,num;
    void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
    int distant(int x,int y,int pos){
        if (dfn[x]<dfn[y])  swap(x,y);
        return min(dis[x]-dis[y],V[pos]-(dis[x]-dis[y]));
    }
    void dfs(int x){
        dfn[x]=++Time;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]) continue;
            if (!dfn[son]){
                fa[son]=x,dis[son]=dis[x]+val[p];
                fv[son]=val[p],dfs(son);
            }else   if (dfn[son]<dfn[x]){
                V[++cnt]=val[p],RST.insert(cnt+n,son,0);
                for (int i=x;i!=son;i=fa[i])    V[cnt]+=fv[i];
                for (int i=x;i!=son;i=fa[i])    RST.insert(cnt+n,i,distant(i,son,cnt));
            }
        }
    }
    void tarjan(int x,int fa){//不论如何枚举顺序都是一样的,那么dfn就算再次dfs也是一样的
        dfn[x]=low[x]=++Time;
        instack[stack[++top]=x]=1;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa)    continue;
            if (!dfn[son])  tarjan(son,x),low[x]=min(low[x],low[son]);
            else    if (instack[son])   low[x]=min(low[x],dfn[son]);
        }
        if (dfn[x]==low[x]){
            belong[x]=++num;
            instack[x]=0;
            while (stack[top]!=x)   belong[stack[top]]=num,instack[stack[top--]]=0;
            top--;
        }
    }
    void init(){
        Time=0;
        memset(dfn,0,sizeof(dfn));
    }
}OT;//Original Tree
struct S3{
    int x,y,z;
    void insert(int _x,int _y,int _z){x=_x,y=_y,z=_z;}
}Line[(N<<1)+10];
int main(){
    n=read(),m=read(),q=read();
    for (int i=1;i<=m;i++){
        int x=read(),y=read(),z=read();
        OT.insert(x,y,z);
        Line[i].insert(x,y,z);
    }
    OT.dfs(1),OT.init(),OT.tarjan(1,0);
    for (int i=1;i<=m;i++)
        if (OT.belong[Line[i].x]!=OT.belong[Line[i].y])
            RST.insert(Line[i].x,Line[i].y,Line[i].z);
    RST.dfs(1),RST.build(1);
    for (int i=1;i<=q;i++){
        int x=read(),y=read();
        node tmp=RST.LCA(x,y);
        if (tmp.lca<=n) printf("%d\n",RST.dis[x]+RST.dis[y]-2*RST.dis[tmp.lca]);
        else{
            int res=RST.dis[x]+RST.dis[y]-RST.dis[tmp.x]-RST.dis[tmp.y];
            res+=OT.distant(tmp.x,tmp.y,tmp.lca-n);
            printf("%d\n",res);
        }
    }
    return 0;
}
posted @ 2019-01-16 21:24  Wolfycz  阅读(...)  评论(...编辑  收藏