Life is a Game 题解(启发式合并)

题目链接

题目思路

查询和修改都离线操作

然后查询使用优先队列进行启发式合并即可

代码

#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int m,n,q;
ll a[maxn];
ll pr[maxn];
int fa[maxn];
int findd(int x){
    return x==fa[x]?x:fa[x]=findd(fa[x]);
}
struct edge{
    int u,v,w;
}e[maxn];
bool cmp(edge a,edge b){
    return a.w<b.w;
}
struct node{
    int k,id;
    friend bool operator<(node a,node b){
        return a.k>b.k;
    }
};
priority_queue<node> pq[maxn];
signed main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        fa[i]=i;
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    }
    sort(e+1,e+1+m,cmp);
    for(int i=1,x,k;i<=q;i++){
        scanf("%d%d",&x,&k);
        pq[x].push({k,i});
    }
    for(int i=1;i<=m;i++){
        int u=findd(e[i].u);
        int v=findd(e[i].v);
        if(u==v) continue;
        while(!pq[u].empty()&&pq[u].top().k+a[u]<e[i].w){
            pr[pq[u].top().id]=pq[u].top().k+a[u];
            pq[u].pop();
        }
        while(!pq[v].empty()&&pq[v].top().k+a[v]<e[i].w){
            pr[pq[v].top().id]=pq[v].top().k+a[v];
            pq[v].pop();
        }
        if(pq[u].size()<pq[v].size()) swap(u,v);
        // v去合并u
        while(pq[v].size()){
            pq[u].push(pq[v].top());
            pq[v].pop();
        }
        a[u]+=a[v];
        fa[v]=u;
    }
    for(int i=1;i<=n;i++){
        while(!pq[i].empty()){
            pr[pq[i].top().id]=pq[i].top().k+a[i];
            pq[i].pop();
        }
    }
    for(int i=1;i<=q;i++){
        printf("%lld\n",pr[i]);
    }
    return 0;
}

posted @ 2021-11-30 15:12  hunxuewangzi  阅读(79)  评论(0编辑  收藏  举报