【CH 弱省互测 Round #1 】OVOO(可持久化可并堆)
Description
给定一颗 \(n\) 个点的树,带边权。
你可以选出一个包含 \(1\) 顶点的连通块,连通块的权值为连接块内这些点的边权和。
求一种选法,使得这个选法的权值是所有选法中第 \(k\) 小的。如果不存在第 \(k\) 小的那输出最大的。
答案对 \(998244353\) 取模。
Hint
- \(1\le n,k\le 10^5\)
- \(\text{边权} \in (0, 10^9]\)
Solution
考虑一个现有的选法,我们考虑如何得到一个新的 尽量小的更大的 选法。
- 将连通块边缘的一条边换下,用另一条与边缘边相邻的边替换。需要在保证新边的边权不小于旧的情况下,新边权最小。
- 在边缘新加入一条最小的边。
我们从初始的选法(只有顶点 \(1\))开始,不断按上述策略拓展出新的选法。如果我们每次 优先拓展权值小的,那么在第 \(k\) 次拓展时我们就得到了答案。
那么现在的问题就是每次拓展如何选边。
我们考虑用一个 堆结构 将每个点所有可以拓展出去的边维护起来。
我们将选法视作一个个状态,每个状态都有一个堆维护 所有待拓展的边缘边。
那么上述两种策略可以转化为:
- 删去堆顶,然后换上新的堆顶。很显然就得到了一个次小选法。
- 选择堆顶对应边另一端的点,表示新拓展的顶点。将该顶点对应出边的边集 合并 到当前堆上。
这里设计到了堆的合并,又不得覆盖原来的信息,那么首选 可持久化左偏树 了。
最后复杂度 \(O((n+k)\log n + k\log k)\)。空间 \(O((n+k)\log n)\)。
Code
/*
* Author : _Wallace_
* Source : https://www.cnblogs.com/-Wallace-/
* Problem : CH 弱省互测 Round #1 OVOO
*/
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int N = 1e5 + 5;
const int mod = 998244353;
int n, k;
int f[N], v[N];
struct Edge {
int to, nxt;
int len;
} e[N];
int head[N], ecnt = 0;
inline void insert(int u, int v, int w) {
e[ecnt] = Edge{v, head[u], w};
head[u] = ecnt++;
}
namespace LefT {
struct lef {
int ch[2], dist;
int end, val;
} tr[N << 5];
int total = 0;
inline int create(int v, int e) {
int x = ++total;
tr[x] = lef{{0, 0}, 1, e, v};
return x;
}
inline int copy(int x) {
return tr[++total] = tr[x], total;
}
int merge(int x, int y) {
if (!x || !y) return x | y;
if (tr[x].val > tr[y].val) swap(x, y);
int z = copy(x);
tr[z].ch[1] = merge(tr[x].ch[1], y);
if (tr[tr[z].ch[0]].dist < tr[tr[z].ch[1]].dist)
swap(tr[z].ch[0], tr[z].ch[1]);
tr[z].dist = tr[tr[z].ch[1]].dist + 1;
return z;
}
};
int root[N];
void prework(int x) {
using namespace LefT;
for (int i = head[x]; ~i; i = e[i].nxt) {
int y = e[i].to, l = e[i].len;
root[x] = merge(root[x], create(l, y));
prework(y);
}
}
struct statu {
int x; long long v;
inline bool operator < (const statu& rhs) const {
return v > rhs.v;
}
}; priority_queue<statu> pq;
signed main() {
ios::sync_with_stdio(false);
memset(head, -1, sizeof(head));
cin >> n >> k;
for (int i = 2; i <= n; i++) {
cin >> f[i] >> v[i];
insert(f[i], i, v[i]);
}
prework(1);
using namespace LefT;
long long ans = 0ll;
pq.push(statu{root[1], tr[root[1]].val});
for (--k; k && !pq.empty(); --k) {
int x = pq.top().x;
long long val = pq.top().v;
pq.pop(), ans = val;
int cur = merge(tr[x].ch[0], tr[x].ch[1]);
if (cur) pq.push(statu{cur, val - tr[x].val + tr[cur].val});
cur = merge(cur, root[tr[x].end]);
if (cur) pq.push(statu{cur, val + tr[cur].val});
}
cout << ans % mod << endl;
}
【CH 弱省互测 Round #1 】OVOO(可持久化可并堆)的更多相关文章
- 弱省互测#0 t2
题意 给定两个字符串 A 和 B,求下面四个问题的答案: 1.在 A 的子串中,不是 B 的子串的字符串的数量. 2.在 A 的子串中,不是 B 的子序列的字符串的数量. 3.在 A 的子序列中,不是 ...
- 弱省互测#2 t3
题意 给出\(n\)个01字节和\(m\)个01字节,要求用后者去匹配前者,两个串能匹配当且仅当除了每个字节末位不同,其他位都要相同.问匹配后者至少有多少个末位不同.(\(1 \le m \le n ...
- 弱省互测#2 t2
题意 给两个树,大小分别为n和m,现在两棵树各选一些点(包括1),使得这棵树以1号点为根同构(同构就是每个点的孩子数目相同),求最大的同构树.(n, m<=500) 分析 我们从两棵树中各取出一 ...
- 弱省互测#1 t3
题意 给出一棵n个点的树,求包含1号点的第k小的连通块权值和.(\(n<=10^5\)) 分析 k小一般考虑堆... 题解 堆中关键字为\(s(x)+min(a)\),其中\(s(x)\)表示\ ...
- 弱省互测#0 t3
Case 1 题意 要求给出下面代码的答案然后构造输入. 给一个图, n 个点 m 条边 q 次询问,输出所有点对之间最大权值最小的路径. 题解 把每一个询问的输出看成一条边,建一棵最小生成树. Ca ...
- 弱省互测#0 t1
题意 给一个\(N \times M\)的01网格,1不能走,从起点\((1, 1)\)走到\((N, M)\),每次只能向下或向右走一格,问两条不相交的路径的方案数.(n, m<=1000) ...
- 【loj2461】【2018集训队互测Day 1】完美的队列
#2461. 「2018 集训队互测 Day 1」完美的队列 传送门: https://loj.ac/problem/2461 题解: 直接做可能一次操作加入队列同时会弹出很多数字,无法维护:一个操作 ...
- luoguP3769 [CH弱省胡策R2]TATT
luoguP3769 [CH弱省胡策R2]TATT PS:做这题前先切掉 P4148简单题,对于本人这样的juruo更助于理解,当然dalao就当练练手吧 题目大意: 现在有n个四维空间中的点,请求出 ...
- 【2018集训队互测】【XSY3372】取石子
题目来源:2018集训队互测 Round17 T2 题意: 题解: 显然我是不可能想出来的……但是觉得这题题解太神了就来搬(chao)一下……Orzpyz! 显然不会无解…… 为了方便计算石子个数,在 ...
随机推荐
- menuconfig
1. menuconfig 的存在意义 原由是 项目的 config 项太多了,需要一个人性化的方式设置. menuconfig 背后是一个应用程序,用户和该应用程序交互,完成 config 设置. ...
- TypeError: Cannot read property 'Component' of undefined
继续跟着阮一峰的教程走,下面写到PropTypes的getDefaultProps时,又出现了问题,基于上一个createClass的报错换成了Component写法 错误描述: 解决方法:引入rea ...
- 利用虚拟化环境虚拟nvme盘
前情介绍 SPDK SPDK的全称为Storage Performance Development Kit ,是Intel发起的一个开源驱动项目,这个是一个开发套件,可以让应用程序在用户态去访问存储资 ...
- yum安装指定版本ceph包
安装ceph包的方式有很多,这里讲的是从官网直接通过yum源的安装方式进行安装 yum源对应的地址为 http://download.ceph.com/rpm-hammer/el6/x86_64/ 怎 ...
- 廖师兄springboot微信点餐开发中相关注解使用解释
package com.imooc.dataobject;import lombok.Data;import org.hibernate.annotations.DynamicUpdate;impor ...
- mysql之多表查询的其他查询
1,临时表查询 (1)需求:查询高于本部门平均工资的人员 select * from person as p, (select dept_id, avg(salary) as '平均工资' from ...
- 面试中AOP这样说,面试官只有一个字:服!
- 插件Spire.PDF帮你高效搞定PDF打印
Spire.PDF介绍 Spire.PDF是一个专业的PDF组件,能够独立地创建.编写.编辑.操作和阅读PDF文件,支持 .NET.Java.WPF和Silverlight.Spire.PDF的PDF ...
- ABBYY FineReader 14新增了什么
FineReader 是一款一体化的 OCR 和PDF编辑转换器,随着版本的更新,功能的增加,FineReader 14的推出继续为用户在处理文档时提高业务生产力,该版本包含若干新特性和功能增强,包括 ...
- 如何用ABBYY FineReader 识别表格
ABBYY FineReader有着强大的OCR文字识别功能,不但可以将文件转换为文本文档或Word文档,也可以识别PDF文件或者图片上的表格,并且转换为Excel文件. 下面小编就使用ABBYY F ...