P5236 【模板】靜態仙人掌圓方樹模板

鏈接: https://www.luogu.org/problem/P5236

題意:

你有一個 n(n<=10000)n(n<=10000) 個點 m(m<=20000)m(m<=20000) 條邊的仙人掌,有 q(q<=10000)q(q<=10000) 個詢問,每次詢問兩個點之間的距離是多少(距離即兩點間的最短路徑)。

代碼

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;

const int maxn=100005;
const int maxm=100005;
int low[maxn],dfn[maxn],dep[maxn],cou;
int len[maxn],n,m,q,fa[maxn][18],sum[maxn][18];
int S[maxn],top,dis[maxn],ed[maxm],totp,ty[maxm];
struct Graph{
    int cnt,nex[maxm],to[maxm];
    int head[maxn],val[maxn];
    Graph(){memset(head,-1,sizeof(head)); cnt=0;}
    void add(int u,int v,int va){
        to[cnt]=v;nex[cnt]=head[u];
        val[cnt]=va; head[u]=cnt++;
    }
}G,Cactu;
void dfs(int u,int f){
    for(int i=Cactu.head[u];~i;i=Cactu.nex[i]){
        int v=Cactu.to[i];
        fa[v][0]=u,dep[v]=dep[u]+1,sum[v][0]=Cactu.val[i];
        dfs(v,u);
    }
}
void deal(int u,int v){
    //記錄整條鏈的長度
    len[++totp]=dis[S[top]]-dis[u]+ed[S[top]];
    //將環上的點取出
    while(1){
        int p=S[top--];
        int x=dis[p]-dis[u],y=len[totp]-x;
        Cactu.add(totp,p,min(x,y));
        ty[p]=(x<=y);
        if(p==v) break;
    }
    Cactu.add(u,totp,0);
}
void tarjan(int u,int f){
    dfn[u]=low[u]=++cou;
    S[++top]=u;
    for(int i=G.head[u];~i;i=G.nex[i]){
        int v=G.to[i];
        if(v==f) continue;

        if(!dfn[v]){
            dis[v]=dis[u]+G.val[i];
            tarjan(v,u);
            //這條邊爲非環邊 直接建圖
            if(low[v]>dfn[u]) top--,Cactu.add(u,v,G.val[i]);
            //如果u和v是恰好連接一個環的邊
            else if (low[v]==dfn[u]) deal(u,v);
            low[u]=min(low[u],low[v]);
        }
        //這條邊連回更小的位置
        else low[u]=min(low[u],dfn[v]),ed[u]=G.val[i];
    }
}
int LCA(int x,int y){
    int ret=0;
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=15;i>=0;i--)
        if(dep[x]-(1<<i)>=dep[y])
            ret+=sum[x][i],x=fa[x][i];
    if(x==y) return ret;
    for(int i=15;i>=0;i--)
        if(fa[x][i]!=fa[y][i]&&fa[x][i]!=-1){
            ret=ret+sum[x][i]+sum[y][i];
            x=fa[x][i],y=fa[y][i];
        }

    if(fa[x][0]<=n) return sum[x][0]+sum[y][0]+ret;
    int a=sum[x][0],b=sum[y][0],add;
    if(ty[x]==ty[y]) add=min(abs(a-b),len[fa[x][0]]-abs(a-b));
    else add=min(a+b,len[fa[x][0]]-a-b);
    return ret+add;
}
int main(){
    scanf("%d%d%d",&n,&m,&q); totp=n;
    rep(i,1,m){
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
        G.add(x,y,z); G.add(y,x,z);
    }
    tarjan(1,-1);
    dfs(1,-1);
    for(int j=1;j<=15;j++){
        for(int i=1;i<=totp;i++){
            sum[i][j]=sum[i][j-1]+sum[fa[i][j-1]][j-1];
            fa[i][j]=fa[fa[i][j-1]][j-1];
        }
    }
    while(q--){
        int u,v; scanf("%d%d",&u,&v);
        printf("%d\n",LCA(u,v));
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章