BZOJ 2125 最短路

Posted on 2017-11-02 16:55  ziliuziliu  阅读(167)  评论(0编辑  收藏  举报

边仙人掌。环上的点全部连向这个环上深度最小的点。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define maxv 500050
#define maxe 1000050
#define inf 0x7f7f7f7f7f7f7f7fLL
using namespace std;
int n,m,qt,x[maxe],y[maxe],w[maxe],u,v,dep[maxv],anc[maxv][21],g[maxv],deps[maxv];
int id[maxv],bel[maxv],len[maxv],tot=0,pre[maxv],st[maxv],top=0,nume=1,prew[maxv],kr=0;
long long dis[maxv];
bool vis[maxv];
struct edge
{
    int v,w,nxt;
}e[maxe];
struct data
{
    int a,b;
    data (int a,int b):a(a),b(b) {}
    data () {}
};
queue <int> q;
int read()
{
    char ch;int data=0;
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9')
    {
        data=data*10+ch-'0';
        ch=getchar();
    }
    return data;
}
void addedge(int u,int v,int w)
{
    e[++nume].v=v;e[nume].w=w;e[nume].nxt=g[u];g[u]=nume;
    e[++nume].v=u;e[nume].w=w;e[nume].nxt=g[v];g[v]=nume;
}
void spfa()
{
    for (int i=2;i<=n;i++) dis[i]=inf;dis[1]=0;
    q.push(1);vis[1]=true;int war=0;
    while (!q.empty())
    {
        war++;
        int head=q.front();q.pop();
        for (int i=g[head];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if (dis[v]>dis[head]+e[i].w)
            {
                dis[v]=dis[head]+e[i].w;dep[v]=dep[head]+1;
                pre[v]=head;prew[v]=e[i].w;
                if (!vis[v]) {vis[v]=true;q.push(v);}
            }
        }
        vis[head]=false;
    }
}
void dfs(int x)
{
    vis[x]=true;
    for (int i=g[x];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if (anc[x][0]==v || vis[v]) continue;
        deps[v]=deps[x]+1;dfs(v);
    }
}
void build()
{
    nume=1;memset(g,0,sizeof(g));memset(vis,false,sizeof(vis));
    for (int i=1;i<=m;i++)
    {
        if (pre[x[i]]==y[i] || pre[y[i]]==x[i]) continue;
        top=0;tot++;
        u=x[i];v=y[i];
        if (dep[u]<dep[v]) swap(u,v);len[tot]=w[i];
        while (dep[u]>dep[v]) {st[++top]=u;bel[u]=1;len[tot]+=prew[u];u=pre[u];}
        while (u!=v) {st[++top]=u;st[++top]=v;bel[u]=1;bel[v]=2;len[tot]+=prew[u]+prew[v];u=pre[u];v=pre[v];}
        for (int j=1;j<=top;j++) {anc[st[j]][0]=u;addedge(st[j],u,dis[st[j]]-dis[u]);id[st[j]]=tot;}
    }
    for (int i=1;i<=m;i++)
    {
        u=x[i];v=y[i];
        if (dep[u]>dep[v]) swap(u,v);
        if (id[u]==id[v] && id[u]) continue;
        if (id[v] && !id[u]) continue;
        anc[v][0]=u;addedge(u,v,w[i]);
    }
    dfs(1);
    for (int e=1;e<=20;e++)
        for (int i=1;i<=n;i++)
            anc[i][e]=anc[anc[i][e-1]][e-1];
}
data lca(int x,int y)
{
    int rx=x,ry=y;
    for (int e=20;e>=0;e--)
    {
        if (deps[anc[x][e]]>=deps[y] && anc[x][e])
            x=anc[x][e];
    }
    if (x==y) return data(x,0);
    for (int e=20;e>=0;e--)
    {
        if (anc[x][e]!=anc[y][e])
        {
            x=anc[x][e];
            y=anc[y][e];
        }
    }
    return data(x,y);
}
long long get_ans(int x,int y)
{
    if (dep[x]>dep[y]) swap(x,y);long long rr,dx,dy;
    dx=dis[x]-dis[anc[x][0]];dy=dis[y]-dis[anc[y][0]];
    if (bel[x]==bel[y]) rr=min(dy-dx,len[id[x]]+dx-dy);
    else rr=min(dx+dy,len[id[x]]-dx-dy);
    return rr;
}
int main()
{
    n=read();m=read();qt=read();
    for (int i=1;i<=m;i++)
    {
        x[i]=read();y[i]=read();w[i]=read();
        addedge(x[i],y[i],w[i]);
    }
    spfa();
    build();
    for (int i=1;i<=qt;i++)
    {
        u=read();v=read();if (deps[u]<deps[v]) swap(u,v);
        data ret=lca(u,v);
        if (!ret.b) printf("%lld\n",dis[u]-dis[ret.a]);
        else
        {
            if (id[ret.a]==id[ret.b] && id[ret.a]) printf("%lld\n",dis[u]+dis[v]-dis[ret.a]-dis[ret.b]+get_ans(ret.a,ret.b));
            else printf("%lld\n",dis[u]+dis[v]-2*dis[anc[ret.a][0]]);   
        }
    }
    return 0;
}