BZOJ2125: 最短路

建出圆方树
对于询问的两个点,倍增找他们的LCA
若是圆点,直接得到答案
若是方点,两边的点先跳到这个环上,然后找环上的最近距离

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

inline void down(int &x,const int &y){if(x>y)x=y;}
const int maxn = 41000;
const int maxd = 17;

int n,m,q;

struct edge
{
    int y,c,nex;
    edge(){}
    edge(const int _y,const int _c,const int _nex){y=_y;c=_c;nex=_nex;}
}a[maxn<<1],b[maxn<<1]; int len,fir[maxn],len2,fir2[maxn];
inline void ins(const int x,const int y,const int c){a[++len]=edge(y,c,fir[x]);fir[x]=len;}
inline void ins2(const int x,const int y,const int c){b[++len2]=edge(y,c,fir2[x]);fir2[x]=len2;}

vector<int>V[maxn]; int cnt,fa[maxn];
int T[maxn],tp;
int did,dfn[maxn],low[maxn];
void tarjan(const int x,const int pre)
{
    dfn[x]=low[x]=++did; T[++tp]=x;
    for(int k=fir[x];k;k=a[k].nex) if(k!=(pre^1))
    {
        const int y=a[k].y;
        if(!dfn[y]) 
        {
            tarjan(y,k); down(low[x],low[y]);
            if(low[y]==dfn[x])
            {
                fa[++cnt]=x; 
                V[cnt].push_back(x); int la=0;
                while(la!=y)
                    V[cnt].push_back(la=T[tp--]);
            }
            else if(low[y]>dfn[x]) tp--;
        }
        else down(low[x],dfn[y]);
    }
}
bool ev[maxn];
void dfs(const int x)
{
    ev[x]=true;
    for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(dfn[y]>dfn[x])
    {
        if(low[y]>dfn[x]) ins2(x,y,a[k].c),ins2(y,x,a[k].c);
        if(!ev[y]) dfs(y);
    }
}
int use[maxn],ci[maxn],ed;
void dfs2(const int x)
{
    for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(use[y]>use[x])
    {
        if(use[x]==1)
        {
            if(use[y]==ed) ci[ed]=a[k].c;
            else ci[1]=a[k].c;
            if(use[y]==ed) continue;
        }
        else ci[use[x]]=a[k].c;
        dfs2(y);
    }
}
int s[maxn],pres[maxn],pid[maxn],sum[maxn];
void build()
{
    dfs(1);
    for(int i=1;i<=cnt;i++)
    {
        for(int j=0;j<V[i].size();j++) use[V[i][j]]=j+1;
        ed=V[i].size(); 
        if(ed==2)
        {
            int x=V[i][0],ct=0;
            for(int k=fir[x],y=a[k].y;k;k=a[k].nex,y=a[k].y) if(use[y])
            {
                if(!ct) ci[1]=a[k].c;
                else ci[2]=a[k].c;
                ct++;
            }
        }
        else dfs2(fa[i]);
        for(int j=1;j<=ed;j++) s[j]=s[j-1]+ci[j];
        sum[i]=s[ed];
        for(int j=0;j<V[i].size();j++)
        {
            int c=min(s[j],s[ed]-s[j]);
            ins2(n+i,V[i][j],c); ins2(V[i][j],n+i,c);
        }
        for(int j=1;j<V[i].size();j++) pid[V[i][j]]=j+1,pres[V[i][j]]=s[j];
        for(int j=0;j<V[i].size();j++) use[V[i][j]]=0;
    }
}
int f[maxn][maxd],dis[maxn][maxd],dep[maxn];
void build_tree(const int x)
{
    for(int i=1;i<maxd;i++)
        f[x][i]=f[f[x][i-1]][i-1],
        dis[x][i]=dis[x][i-1]+dis[f[x][i-1]][i-1];
    for(int k=fir2[x],y=b[k].y;k;k=b[k].nex,y=b[k].y) if(y!=f[x][0])
        dep[y]=dep[x]+1,f[y][0]=x,dis[y][0]=b[k].c,build_tree(y);
}
void lca(int x,int y,int &top,int &L)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=maxd-1;i>=0;i--) if(dep[x]-dep[y]>=(1<<i)) L+=dis[x][i],x=f[x][i];
    if(x==y) { top=x; return; }
    for(int i=maxd-1;i>=0;i--) if(f[x][i]!=f[y][i])
        L+=dis[x][i],x=f[x][i],
        L+=dis[y][i],y=f[y][i];
    L+=dis[x][0]+dis[y][0];
    top=f[x][0];
}

int main()
{
    scanf("%d%d%d",&n,&m,&q);
    len=1;
    for(int i=1;i<=m;i++)
    {
        int x,y,c; scanf("%d%d%d",&x,&y,&c);
        ins(x,y,c); ins(y,x,c);
    }
    did=cnt=0; tarjan(1,0);
    len2=0; build();
    dep[1]=1; build_tree(1);

    int ti=0;
    while(q--)
    {
        ++ti;
        int x,y; scanf("%d%d",&x,&y);
        int top,l=0;
        lca(x,y,top,l);
        if(top>n)
        {
            l=0;
            for(int i=maxd-1;i>=0;i--) if(dep[x]-(dep[top]+1)>=(1<<i))
                l+=dis[x][i],x=f[x][i];
            swap(x,y);
            for(int i=maxd-1;i>=0;i--) if(dep[x]-(dep[top]+1)>=(1<<i))
                l+=dis[x][i],x=f[x][i];
            if(pid[x]>pid[y]) swap(x,y);
            l+=min(pres[y]-pres[x],sum[top-n]-pres[y]+pres[x]);
            printf("%d\n",l);
        }
        else printf("%d\n",l);
    }

    return 0;
}

发布了539 篇原创文章 · 获赞 28 · 访问量 23万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览