当前位置:网站首页>2021ICPC上海 H.Life is a Game Kruskal重构树
2021ICPC上海 H.Life is a Game Kruskal重构树
2022-07-07 21:50:00 【HeartFireY】
H.Life is a Game Kruskal重构树
题目分析
给定一张 n n n个点 m m m条边的无向图,以及 q q q个询问。对于每个询问,给定初始点和初始经验值,经过一条边要求当前经验值大于边权,经过一个点后点权累加至经验值。求能够获得的最大经验。
首先容易证明,对于最终的答案,两个点之间的所有简单路径上最大边权的最小值 = 最小生成树上两个点之间的简单路径上的最大值 = K r u s k a Kruska Kruskal 重构树上两点之间的 L C A LCA LCA 的权值
那么容易想到对原图建 K r u s k a l Kruskal Kruskal重构树,不妨先对样例建树:
红色数字表示 K r u s k a l Kruskal Kruskal重构树的点权,即为原图最大边权最小值。叶节点均为原图节点,黑色数字表示经验值,由于后期计算方便需要,将经验值自叶子节点向根节点求和。
那么我们对于某个询问,只需要从对应的叶节点开始往上跳到祖先节点,直至跳不过去(经验值小于点权(红色数字)),同时我们处理出了到达每个父节点能够获得的经验值(黑色数字),这样只需要一路往上跳检查是否满足经验值大于 K r u s k a l Kruskal Kruskal重构树的点权值就可以了。
Code
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10;
int n, m, q;
int pnt[N], val[N];
struct unionfind{
int par[N];
unionfind(int n){
for(int i = 1; i <= n; i++) par[i] = i; }
int find(int x){
return x == par[x] ? x : (par[x] = find(par[x])); }
void merge(int u, int v){
int fau = find(u), fav = find(v);
if(fau != fav) par[fav] = fau;
}
int ismerge(int u, int v){
return find(u) == find(v); }
};
vector<int> g[N];
namespace KR{
struct edge{
int u, v ,w;
const bool operator< (const edge &x) const {
return w < x.w; }
}edges[N];
inline void add_edge(int i, int u, int v, int w){
edges[i] = {
u ,v, w}; }
int kruskal(){
int tot = n, cnt = 0;
unionfind uf(n + 20);
sort(edges + 1, edges + 1 + m);
for(int i = 1; i <= m; i++){
int nu = edges[i].u, nv = edges[i].v, nw = edges[i].w;
int fau = uf.find(nu), fav = uf.find(nv);
if(fau != fav){
val[++tot] = edges[i].w;
uf.par[tot] = uf.par[fau] = uf.par[fav] = tot;
g[fau].emplace_back(tot), g[fav].emplace_back(tot);
g[tot].emplace_back(fau), g[tot].emplace_back(fav);
cnt++;
}
if(cnt == n - 1) break;
}
return tot;
}
}
int fa[N][20];
void dfs0(int u, int ufa){
fa[u][0] = ufa;
for(int i = 1; i < 20; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
for(auto v : g[u]){
if(v == ufa) continue;
dfs0(v, u);
pnt[u] += pnt[v];
}
}
using KR::add_edge;
using KR::kruskal;
inline void solve(){
cin >> n >> m >> q;
for(int i = 1; i <= n; i++) cin >> pnt[i];
for(int i = 1; i <= m; i++){
int u, v, w; cin >> u >> v >> w;
add_edge(i, u, v ,w);
}
n = kruskal();
dfs0(n, 0);
val[0] = 1e18;
while(q--){
int u, s; cin >> u >> s;
int ans = pnt[u] + s;
while(u != n){
int t = u;
for(int i = 19; i >= 0; i--)
if(val[fa[u][i]] <= ans) u = fa[u][i];
if(t == u) break;
ans = pnt[u] + s;
}
cout << ans << endl;
}
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
solve();
return 0;
}
边栏推荐
- GEE(三):计算两个波段间的相关系数与相应的p值
- 小程序多种开发方式对比-跨端?低代码?原生?还是云开发?
- [language programming] exe virus code example
- 智慧社区和智慧城市之间有什么异同
- Cascade-LSTM: A Tree-Structured Neural Classifier for Detecting Misinformation Cascades-KDD2020
- Microbial Health Network, How to restore Microbial Communities
- What is fake sharing after filling the previous hole?
- Bit operation
- Network security - information query of operating system
- OC variable parameter transfer
猜你喜欢
消息队列与快递柜之间妙不可言的关系
PCL . VTK files and Mutual conversion of PCD
iNFTnews | Web5 vs Web3:未来是一个过程,而不是目的地
STL标准模板库(Standard Template Library)一周学习总结
数据库每日一题---第22天:最后一次登录
ArcGIS:字段赋值_属性表字段计算器(Field Calculator)依据条件为字段赋值
Software test classification
十三、系统优化
What is fake sharing after filling the previous hole?
U盘拷贝东西时,报错卷错误,请运行chkdsk
随机推荐
Clean C disk
数据库每日一题---第22天:最后一次登录
14、 Two methods of database export and import
微信论坛交流小程序系统毕业设计毕设(3)后台功能
智慧社区和智慧城市之间有什么异同
What does the model number of asemi rectifier bridge kbpc1510 represent
为什么市场需要低代码?
Network security - Eternal Blue
Network security -beef
Installing vmtools is gray
Adrnoid开发系列(二十五):使用AlertDialog创建各种类型的对话框
Inftnews | the wide application of NFT technology and its existing problems
消息队列与快递柜之间妙不可言的关系
30讲 线性代数 第五讲 特征值与特征向量
USB (十八)2022-04-17
Database daily question --- day 22: last login
Talk about DART's null safety feature
Microbial health network, how to restore microbial communities
Personal statement of testers from Shuangfei large factory: is education important for testers?
Brush question 5