codeforces 1051F (树+ 最短路)

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

题意: 现在给你n个点和m条边组成一个图,有q个询问每次问你从x点到y点的最短路径。但是这里有个限制条件就是m最多比n大20 而且保证一定联通。

思路: 这个题当然就是抓住 m-n <=20  这个限制条件。  那么对于这个题,我如抽出来n-1条边组成一棵树,先不考虑剩下的边,那么问题就简化了,就是求个lca。 然后我考虑剩下的边,那么就是剩下的x条边,也就是最多40个点,那么我可以对这40个点跑个最短路,那么任意两点的距离不就是uv到lca  和 通过特殊的40个的最短路。

代码:

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<ll,int > pli;
const ll inf=1e18+5;
const int N =1e5+35;
const int DEG=21;
ll dis[55][N];
struct Edge
{
    int u;
    int v;
    int next;
    ll w;
}edge1[N*2],edge[N*2];
int tot1;
int head1[N];
int tot;
int head[N];
int f[N];
int fa[N][25];
int deg[N];
ll dep[N];
int n,m;
int se[50];
int scnt;
int vis[N];

vector<Edge> ve[N];

void adde1(int u,int v,ll w)
{
    edge1[++tot1].u=u;
    edge1[tot1].v=v; edge1[tot1].w=w; edge1[tot1].next=head1[u]; head1[u]=tot1;
}

void add(int u,int v,ll w)
{
    edge[++tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot;
}

void init()
{
    tot=tot1=0;
    memset(head,-1,sizeof(head));
    memset(head1,-1,sizeof(head1));
}

void bfs(int rt)
{
    queue<int >que;
    deg[rt]=0;
    dep[rt]=0;
    fa[rt][0]=rt;
    que.push(rt);
    while(!que.empty())
    {
        int tmp=que.front();
        que.pop();
        for(int i=1;i<DEG;i++){
            fa[tmp][i]=fa[fa[tmp][i-1]][i-1];
        }
        for(int i=head[tmp];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(v==fa[tmp][0]) continue;
            deg[v]=deg[tmp]+1;
            dep[v]=dep[tmp]+edge[i].w;
            fa[v][0]=tmp;
            que.push(v);
        }
    }
}

int LCA(int u,int v)
{
    if(deg[u]>deg[v]) swap(u,v);
    int hu=deg[u]; int hv=deg[v];
    int tu=u, tv=v;
    for(int det=hv-hu,i=0;det;det>>=1,i++){
        if(det&1) tv=fa[tv][i];
    }
    if(tu==tv) return tu;
    for(int i=DEG-1;i>=0;i--){
        if(fa[tu][i]==fa[tv][i]) continue;
        tu=fa[tu][i];
        tv=fa[tv][i];
    }
    return fa[tu][0];
}

bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}

void dij(int id,int s)
{
    for(int i=0;i<=n+2;i++){
        vis[i]=0;
        dis[id][i]=inf;
    }
    dis[id][s]=0;
    priority_queue<pli,vector<pli>,greater<pli> >q;
    q.push(pli(0,s));

    while(!q.empty())
    {
        pli tmp=q.top();
        q.pop();
        int u=tmp.second;
        if(tmp.first>dis[id][u]) continue;
        vis[u]=1;

        for(int i=0;i<ve[u].size();i++){
            int v=ve[u][i].v;
            ll w=ve[u][i].w;
            if(vis[v]) continue;
            if(dis[id][v]>dis[id][u]+w)
            {
                dis[id][v]=dis[id][u]+w;
                q.push(pli(dis[id][v],v));
            }
        }
    }

}

int getf(int x)
{
    return f[x]==x?x:(f[x]=getf(f[x]));
}

int merge(int x,int y)
{
    int t1=getf(x);
    int t2=getf(y);
    if(t1!=t2){
        f[t2]=t1;
        return 1;
    }
    return 0;
}

int main()
{
    scanf("%d %d",&n,&m);
    int u,v; ll w;
    init();
    for(int i=1;i<=m;i++){
        scanf("%d %d %lld",&u,&v,&w);
        adde1(u,v,w);
        ve[u].push_back((Edge){u,v,0,w});
        ve[v].push_back((Edge){v,u,0,w});
    }

    sort(edge1+1,edge1+tot1+1,cmp);
    for(int i=0;i<=n+2;i++){
        f[i]=i;
    }
    for(int i=1;i<=tot1;i++){
        u=edge1[i].u; v=edge1[i].v;
        if(merge(u,v)){
            add(u,v,edge1[i].w);
            add(v,u,edge1[i].w);
        }
        else{
            se[++scnt]=u;
            se[++scnt]=v;
        }
    }

    bfs(1);

    sort(se+1,se+scnt+1);
    scnt=unique(se+1,se+scnt+1)-(se+1);
    for(int i=1;i<=scnt;i++){
        dij(i,se[i]);
    }

    int q;
    scanf("%d",&q);
    while(q--)
    {
        scanf("%d %d",&u,&v);
        ll ans=inf;
        int lca=LCA(u,v);
        ans=dep[u]+dep[v]-2*dep[lca];
        for(int i=1;i<=scnt;i++){
            ans=min(ans,dis[i][u]+dis[i][v]);
        }
        printf("%lld\n",ans);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/yjt9299/article/details/82805886
今日推荐