【2021ICPC上海站】H-Life is a Game(kruskal重构树)
题意
你本身有一个权值。
每个点有一个权值,到达一个点可以获得这个权值;
每条边也有一个权值,只有你自己当前权值大于等于边权才可以走这条边。
q次询问,每次给出初始点和初始边权,输出可获得的最大边权。
思路
krustal重构树
一个点可以获得自己子树所有点权之和。
子树求和 + 倍增跳就好了
代码
#include<bits/stdc++.h> using namespace std; #define pii pair<int,int> #define int long long const int N=2e5+10; vector<tuple<int,int,int> >es; vector<int> g[N]; int be,k; int n,m,q; int fa[N]; int f[N][21],sz[N]; int val[N],cnt; int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } void krus(){ cnt=n;//--------- for(int i=1;i<=n;i++) fa[i]=i; sort(es.begin(),es.end()); int u,v,w; for(int i=0;i<m;i++){ tie(w,u,v)=es[i]; u=find(u),v=find(v); if(u!=v){ val[++cnt]=w; fa[cnt]=fa[u]=fa[v]=cnt; g[u].push_back(cnt); g[cnt].push_back(u); g[v].push_back(cnt); g[cnt].push_back(v); } } } void dfs(int u,int father){ f[u][0]=father; for(int i=1;i<=20;i++){ f[u][i]=f[f[u][i-1]][i-1]; } for(int v: g[u]) { if(v!=father){ dfs(v,u); sz[u]+=sz[v]; } } } void solve(){ cin>>n>>m>>q; for(int i=1;i<=n;i++) cin >> sz[i]; for(int i=0;i<m;i++){ int u,v,w; cin>>u>>v>>w; es.emplace_back(w,u,v); } krus(); dfs(cnt,0); val[0]=1e18+7; while(q--){ cin>>be>>k; int ans=k+sz[be]; while(be!=cnt){ int x=be; for(int i=20;i>=0;i--){ if(val[f[be][i]]<=ans) be=f[be][i]; } if(x==be) break; ans=sz[be]+k; } cout<<ans<<endl; } } signed main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t=1; while(t--) solve(); return 0; }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16667263.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步