codeforces1253F(图转换为树减少复杂度)

题意:

给定一个无向图,其中1-k为充电桩,然后给定q个询问\(u_i, v_i\)(都是充电桩),然后问从其中一个充电桩到达另外一个充电桩需要最小的电池的容量。
每经过一条边都需要消耗一定的能量,到达另外一个充电桩会自动的把电充好。

题解

首先计算每个非充电桩的点到充电桩的最短距离
然后对于每一条边u-v,我们计算他们到各自的充电桩的最短距离+边权重,然后把u'-v',dis_u+dis_v+w加到新的图中
然后就是并查集,注意合并是有序的

最后查询利不断的向上就能进行查询了。

代码

#include<bits/stdc++.h>
#define mp std::make_pair
using namespace std;

typedef long long LL;
typedef std::pair<int,int> pi;

const int N=100005;
const LL inf=(LL)1e15;

int n,m,k,q,cnt,last[N],fro[N],f[N],sz[N];
LL dis[N],val[N];
struct edge{int to,next;LL w;}e[N*6];
struct data{int x,y;LL w;}a[N*3];
std::priority_queue<std::pair<LL,int> > que;
bool vis[N];

void addedge(int u,int v,LL w)
{
    e[++cnt].to=v;e[cnt].w=w;e[cnt].next=last[u];last[u]=cnt;
    e[++cnt].to=u;e[cnt].w=w;e[cnt].next=last[v];last[v]=cnt;
}

void dij()
{
    for (int i=1;i<=k;i++) dis[i]=0,fro[i]=i,que.push(mp(0,i));
    for (int i=k+1;i<=n;i++) dis[i]=inf;
    while (!que.empty())
    {
        int u=que.top().second;que.pop();
        if (vis[u]) continue;
        vis[u]=1;
        for (int i=last[u];i;i=e[i].next)
            if (dis[u]+e[i].w<dis[e[i].to])
            {
                dis[e[i].to]=dis[u]+e[i].w;
                fro[e[i].to]=fro[u];
                que.push(mp(-dis[e[i].to],e[i].to));
            }
    }
}

bool cmp(data a,data b)
{
    return a.w<b.w;
}
//没有进行路径的压缩
int find(int x)
{
    return f[x]==x?x:find(f[x]);
}

LL query(int x,int y)
{
    LL ans=0;
    while (x!=y)
    {
        if (sz[x]>sz[y]) std::swap(x,y);
        ans=std::max(ans,val[x]);x=f[x];
    }
    return ans;
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&q);
    for (int i=1;i<=m;i++)
    {
        int x,y;LL w;scanf("%d%d%lld",&x,&y,&w);
        addedge(x,y,w);
    }
    dij();
    for (int i=1;i<=cnt;i+=2)
    {
        int x=e[i].to,y=e[i+1].to;LL w=dis[x]+dis[y]+e[i].w;
        //fro[i] i最短路要经过哪个电桩
        a[i/2+1]=(data){fro[x],fro[y],w};
    }
    std::sort(a+1,a+m+1,cmp);

    for (int i=1;i<=k;i++) f[i]=i,sz[i]=1;
    //有点最小生成树的感觉。
    for (int i=1;i<=m;i++)
    {
        cout<<a[i].x<<" "<<a[i].y<<" "<<a[i].w<<endl;
        int x=find(a[i].x),y=find(a[i].y);
        if (x==y) continue;
        cout<<"test "<<x<<" "<<y<<endl;
        if (sz[x]>sz[y]) std::swap(x,y);
        f[x]=y;sz[y]+=sz[x];val[x]=a[i].w;
    }
    while (q--)
    {
        int x,y;scanf("%d%d",&x,&y);
        printf("%lld\n",query(x,y));
    }
    return 0;
}
/*
9 11 3 2
1 3 99
1 4 5
4 5 3
5 6 3
6 4 11
6 7 21
7 2 6
7 8 4
8 9 3
9 2 57
9 3 2
3 1
2 3
*/

猜你喜欢

转载自www.cnblogs.com/babydragon/p/11876723.html