【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;
}