当前位置: 首页 > news >正文

带修主席树模板

洛谷模板题已过【P2617 Dynamic Rankings】

/* 动态持久化线段树(树状数组套线段树)模板类* 用于解决带修改的区间第k小和区间排名查询问题* 核心功能:*   - 单点更新 O(log n log V)*   - 区间第k小查询 O(log n log V)*   - 区间排名查询 O(log n log V)*/
template<class Node>
struct DynamicPersistentSegmentTree {int n;                 // 原数组大小(树状数组大小)int V;                 // 离散化后的值域范围 [1, V]int tot = 0;           // 线段树节点计数器vector<Node> tr;       // 线段树节点池vector<int> roots;     // 树状数组的根节点数组(下标1~n)vector<int> arrL,arrR; // 临时存储树状数组路径节点DynamicPersistentSegmentTree(int n_, int V_) : n(n_), V(V_) {tr.reserve(n * __lg(n) * __lg(V) * 4);tr.resize(1);tr[0] = Node();roots.assign(n + 1, 0);}/* 单点更新操作* @param pos: 原数组位置 (1-indexed)* @param val: 离散化后的权值* @param w: 更新值* 时间复杂度:O(log n * log V)*/void update(int pos, int val, int w) {// 树状数组遍历:更新所有包含pos的线段树for (int i = pos; i <= n; i += i & -i) {roots[i] = insert(roots[i], 1, V, val, w);}}/* 区间第k小查询* @param l: 区间左端点 (1-indexed)* @param r: 区间右端点 (1-indexed)* @param k: 查询的排名* @return: 离散化后的权值* 时间复杂度:O(log n * log V)*/int query_kth(int l, int r, int k) {get_roots(l - 1, arrL);get_roots(r, arrR);return query_kth(arrL, arrR, k, 1, V);}/* 区间排名查询(小于x的数的个数)* @param l: 区间左端点* @param r: 区间右端点* @param x: 离散化后的权值* @return: 排名值* 时间复杂度:O(log n * log V)*/int query_rank(int l, int r, int x) {get_roots(l - 1, arrL);get_roots(r, arrR);return query_rank(arrL, arrR, 1, V, x);}private:int insert(int now, int l, int r, int pos, int w) {if (!now) {now = ++tot;        tr[now] = Node();    }tr[now].v += w;           if (l == r) {return now;  }int mid = (l + r) >> 1;    if (pos <= mid) {tr[now].l = insert(tr[now].l, l, mid, pos, w);}else {tr[now].r = insert(tr[now].r, mid + 1, r, pos, w);}return now;}void get_roots(int x, vector<int>& arr) {arr.clear();while (x) {arr.push_back(roots[x]);x -= x & -x;}}int query_kth(vector<int>& arrL, vector<int>& arrR, int k, int l, int r) {if (l == r) {return l;}int mid = (l + r) >> 1;int sum = 0;// 计算左子树的总和(右区间和 - 左区间和)for (int i : arrR) {sum += tr[tr[i].l].v;  // 累加右区间左子树}for (int i : arrL) {sum -= tr[tr[i].l].v;  // 减去左区间左子树}if (k <= sum) {for (int& i : arrL) {i = tr[i].l;}for (int& i : arrR) {i = tr[i].l;}return query_kth(arrL, arrR, k, l, mid);}else {for (int& i : arrL) {i = tr[i].r;}for (int& i : arrR) {i = tr[i].r;}return query_kth(arrL, arrR, k - sum, mid + 1, r);}}int query_rank(vector<int>& arrL, vector<int>& arrR, int l, int r, int x) {if (x < l) {return 0;}if (x >= r) {// 目标值大于等于当前区间:返回整个区间计数int sum = 0;for (int i : arrR) {sum += tr[i].v;    // 右区间总和}for (int i : arrL) {sum -= tr[i].v;    // 减去左区间总和}return sum;}int mid = (l + r) >> 1;if (x <= mid) {// 目标值在左子树:所有节点向左移动for (int& i : arrL) {i = tr[i].l;}for (int& i : arrR) {i = tr[i].l;}return query_rank(arrL, arrR, l, mid, x);}else {// 目标值在右子树:先计算左子树总和int sum = 0;for (int i : arrR) {sum += tr[tr[i].l].v;    // 右区间左子树和}for (int i : arrL) {sum -= tr[tr[i].l].v;    // 减去左区间左子树和}for (int& i : arrL) {i = tr[i].r;}for (int& i : arrR) {i = tr[i].r;}return sum + query_rank(arrL, arrR, mid + 1, r, x);}}
};struct Node {int l, r, v;Node(): l(0), r(0), v(0) {}
};
http://www.aitangshan.cn/news/1021.html

相关文章:

  • nebulagraph 查询IO下推总结
  • base_test中的task A,在用例中也写上一个task A,但是这个task A在base_test中调用,实际执行的是用例中的task A,还是base test中的task A
  • LeetCode 面试经典 150_数组/字符串_O(1)时间插入、删除和获取随机元素(12_380_C++_中等)(哈希表) - 教程
  • youwiki大佬的博文
  • 数字化转型别再堆工具了!这款项目管理软件才是破局关键
  • 20250812
  • 数据结构复习第一天(2025/8/12)
  • FWT小记
  • 数字孪生技术是如何在智慧园区领域稳步发展的?
  • 软工8.12
  • nim语言配置nimble路径
  • 4.7 浅拷贝和深拷贝(只针对可变类型:列表、字典、集合)
  • 监控、日志与运维瓶颈
  • 2025 化工材料PLM选型优先级:从国产适配到全球化协同的 TOP5 PLM厂商优选清单
  • Slack推出企业级AI搜索功能,整合全域知识库
  • 流程行业PLM是什么?化工材料/食品饮料/日化美妆等行业PLM选型指南
  • 璞公英公开课回顾 | 高三物理九月调考高频考点解析 高考物理备考策略干货大放送!
  • 国产PLM系统有哪些品牌?2025主流十大国产PLM系统大揭秘!
  • spaCy v3配置与项目系统解析
  • R语言中将行名改为第一列
  • 打印trans的小tips
  • 关于uvm_reg_data_t
  • Gin网站部署
  • 2025-08-04 模拟赛总结
  • 2025-08-07 模拟赛总结(还没写)
  • uvm十万个为什么
  • 2025-08-12 模拟赛总结(还没写)
  • 2025-07-30 模拟赛总结(还没写)
  • ctfshow ssrf web351-360
  • 构建百万级实时排行榜:Redis Sorted Set 与 Java 实战指南