F. The Shortest Statement(图论 树上加边)

http://codeforces.com/problemset/problem/1051/F

题意:

给出n个点,m条边, m n 20 m-n\leq 20 ,边权。每次询问两个点之间的距离。

解析:

相当于树上添加21条边。对于一对点,原树上的距离可以用lca算出。考虑通过新加的边的路径。我们可以对涉及到的点,建立一个新的图(最多44个点),每次在新图跑一个最短路即可。

代码:

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

int n,m,q;
const int maxn=1e5+9;
int head[maxn],nex[maxn<<1],to[maxn<<1],now;
LL val[maxn<<1];
void add(int a,int b,LL v){
    nex[++now]=head[a];head[a]=now;to[now]=b;val[now]=v;
}

bool vis[maxn];
vector<int>V;

struct node{
    int p;LL v;
    bool operator<(const node &A)const{
        return v>A.v;
    }
}tmp;
vector<node>E[maxn]; // 新图

int deep[maxn];
LL len[maxn];
int pa[maxn][30];
void dfs(int p,int fa,int d,LL l){
    vis[p]=1;
    pa[p][0]=fa;
    deep[p]=d;len[p]=l;
    for(int i=head[p];i;i=nex[i]){
        int u=to[i];
        if(u==fa)continue;
        if(vis[u]){
            V.push_back(p);
            V.push_back(u);
            tmp.p=p;
            tmp.v=val[i];
            E[u].push_back(tmp);
        }
        else{
            dfs(u,p,d+1,l+val[i]);
        }
    }
}
void init(){
    for(int i=1;(1<<i)<=n;i++){
        for(int j=1;j<=n;j++){
            pa[j][i]=pa[pa[j][i-1]][i-1];
        }
    }
}
int lca(int a,int b){
    if(deep[a]>deep[b])swap(a,b);
    int i;
    for(i=0;(1<<i)<deep[b];i++);i--;
    for(;;){
        if(deep[a]==deep[b])break;
        if(deep[b]-deep[a]<(1<<i))i--;
        else b=pa[b][i];
    }
    for(i=0;(1<<i)<deep[b];i++);i--;
    for(;;){
        if(a==b)return a;
        if(pa[a][0]==pa[b][0])return pa[a][0];
        if(pa[a][i]==pa[b][i])i--;
        else a=pa[a][i],b=pa[b][i];
    }
}
inline LL getLen(int a,int b){
    int f=lca(a,b);
    return len[a]+len[b]-2*len[f];
}

LL dis[maxn];
priority_queue<node>Q;
LL dij(int st,int en){
    for(auto P:V)dis[P]=2e18,vis[P]=0;
    dis[en]=2e18;
    dis[st]=0;
    vis[st]=vis[en]=0;

    while(!Q.empty())Q.pop();
    Q.push((node){st,0});
    while(!Q.empty()){
        int p=Q.top().p;Q.pop();
        if(vis[p])continue;
        vis[p]=1;
        if(p==en)return dis[p];
        for(auto P:E[p]){
            if(vis[P.p])continue;
            if(dis[p]+P.v<dis[P.p]){
                dis[P.p]=dis[p]+P.v;
                Q.push((node){P.p,dis[P.p]});
            }
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    rep(i,1,m){
        int a,b;LL v;scanf("%d%d%lld",&a,&b,&v);
        add(a,b,v);add(b,a,v);
    }
    dfs(1,0,0,0);
    init();
    sort(V.begin(),V.end());
    V.erase(unique(V.begin(),V.end()),V.end());
    rep(i,0,(int)V.size()-2){
        rep(j,i+1,(int)V.size()-1){
            tmp.p=V[i];
            tmp.v=getLen(V[i],V[j]);
            E[V[j]].push_back(tmp);
            tmp.p=V[j];
            E[V[i]].push_back(tmp);
        }
    }

    scanf("%d",&q);
    while(q--){
        int a,b;scanf("%d%d",&a,&b);
        for(auto P:V){
            tmp.p=P;
            tmp.v=getLen(P,a);
            E[a].push_back(tmp);
            tmp.p=b;
            tmp.v=getLen(P,b);
            E[P].push_back(tmp);
        }
        printf("%lld\n",min(getLen(a,b),dij(a,b)));
        for(auto P:V){
            E[a].pop_back();
            E[P].pop_back();
        }
    }
}
发布了723 篇原创文章 · 获赞 314 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/103190881