2021ICPC上海 H.Life is a Game (kruskal重构树、倍增)

文章目录


题目链接:LifeisaGame
n n n 个点, m m m 条边的无向连通图。
每个点上有个能力值,经过点时可以获得该能力值 a i ai ai,但每个点只能获得一次。
每条边上有个能力值限制 w i wi wi,只有当能力值超过 w i wi wi 时才能通过这条边。
Q Q Q 次询问,每次询问给出初始位置 x x x 和初始能力值 k k k,询问能获得的最大能力值是多少。
n , m , q < = 1 e 5 , a i < = 1 e 4 , w i < = 1 e 9 n,m,q<=1e5 , ai<=1e4 , wi<=1e9 n,m,q<=1e5,ai<=1e4,wi<=1e9

qwq铁了赛上读了今天才补题 之前其实听过重构树但是觉得啊不用学的啦
题解:
k r u s k a l kruskal kruskal重构树就是一颗二叉树 原先的点都是叶子节点
L C A ( u , v ) LCA(u,v) LCA(u,v)的权值是 原图 u u u v v v 路径上最大/小边权的最小/大值(由建树时边权的排序方式决定)
因为这个我们可以找存能量值为边集,然后用链上所需要的能量值max来判断能不能取得这个能量值
q1e5所以要一个 l o g log log 查询
因为是贪心的存一个虚拟的点再往上,所以只要能上去就能走到另一边

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int n, m, q;
int a[N];
int fa[N];
int f[N][31], cost[N][31];
struct node {
    int u, v, w;
}e[N];
bool cmp(node a, node b) {
    return a.w<b.w;
}
int findf(int x) {
    if(fa[x]==x) return x;
    return fa[x]=findf(fa[x]);
}
int cnt;
void kruskal() {
    cnt=n;
    int tot=0;
    for(int i=1; i<=n+n; i++) fa[i]=i;
    for(int i=1; i<=m; i++) {
        int w=e[i].w;
        int u=findf(e[i].u);
        int v=findf(e[i].v);
        if(u!=v) {
            a[++cnt]=a[u]+a[v];
            fa[u]=fa[v]=f[u][0]=f[v][0]=cnt;
            cost[u][0]=w-a[u];
            cost[v][0]=w-a[v];
            ++tot;
        }
        if(tot==n-1) break;
    }
}
signed main() {
    cin>>n>>m>>q;
    for(int i=1; i<=n; i++) cin>>a[i];
    for(int i=1; i<=m; i++) cin>>e[i].u>>e[i].v>>e[i].w;
    sort(e+1, e+1+m, cmp);
    kruskal();
    a[0]=a[cnt];//没懂没写上gg
    int lg=log2(cnt)+1;
    for(int j=1; j<=lg; j++) {
        for(int i=1; i<=cnt; i++) {
            f[i][j]=f[f[i][j-1]][j-1];
            cost[i][j]=max(cost[i][j-1], cost[f[i][j-1]][j-1]);//两半的max
        }
    }
    while(q--) {
        int x, k;
        cin>>x>>k;
        for(int i=lg; i>=0; i--) if(cost[x][i]<=k) x=f[x][i];
		cout<<a[x]+k<<endl;
    }
    return 0;
}

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值