BZOJ2125: 最短路

来源:互联网 发布:zola算法美队2 编辑:程序博客网 时间:2024/05/29 06:31

建出圆方树
对于询问的两个点,倍增找他们的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 1e9using 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;}