整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


题目链接

https://nanti.jisuanke.com/t/42586

Problem

给定一个 nnn 个点的树,以及参数 kkk,树上每个点均有一个权值 vali\mathrm{val}_ivali​。

询问树上有序对 (x,y)(x,y)(x,y) 的数量,满足以下条件:

  • xxx 不等于 yyy
  • xxx 不是 yyy 的祖先
  • yyy 不是 xxx 的祖先
  • xxx 和 yyy 之间的距离不超过 kkk
  • valx+valy=2×vallca(x,y)\mathrm{val}_x+\mathrm{val}_y=2\times \mathrm{val}_{\mathrm{lca}(x,y)}valx​+valy​=2×vallca(x,y)​​

n,k≤105n,k\le 10^5n,k≤105,0≤vali≤n0\le \mathrm{val}_i\le n0≤vali​≤n。

Solution

树上统计问题,发现问题可以划分成子树的问题,显然考虑树上启发式合并。

树上两点间距离问题考虑分析 lca(x,y)\mathrm{lca}(x,y)lca(x,y),假设已知 lca(x,y)=z\mathrm{lca}(x,y)=zlca(x,y)=z,考虑统计以 zzz 的为根的子数中,对答案有贡献的点对 (x,y)(x,y)(x,y) 的数量。

我们在树上启发式合并枚举到第 iii 课子树的时候,统计与前 i−1i-1i−1 棵子树之间的贡献即可。

考虑从给定的五个条件出发分析。条件五:valx+valy=2×vallca(x,y)=z\mathrm{val}_x+\mathrm{val}_y=2\times \mathrm{val}_{\mathrm{lca}(x,y)=z}valx​+valy​=2×vallca(x,y)=z​,显然此时 valx\mathrm{val}_xvalx​ 和 valz\mathrm{val}_{z}valz​ 都已经确定了,那么我们就可以得到 valy=2×valz−valx\mathrm{val}_y=2\times \mathrm{val}_z-\mathrm{val}_xvaly​=2×valz​−valx​。

考虑条件四, xxx 和 yyy 之间的距离不超过 kkk。我们已经知道了 dxd_xdx​ 和他们的 lca\mathrm{lca}lca 的深度 dzd_zdz​,显然可以得到 dy=k−dx+2×dzd_y=k-d_x+2\times d_zdy​=k−dx​+2×dz​。

综上所述,问题转化为了,求前 i−1i-1i−1 子树中深度不超过 dyd_ydy​ 且点的权值为 valy\mathrm{val}_yvaly​ 的点的个数。

考虑 val≤105\mathrm{val}\le 10^5val≤105,可以直接维护权值,对于每一个权值,建一个平衡树,即建立 n+1n+1n+1 棵平衡树,以深度为下标序列,维护该权值的点在每个深度的点的个数。

考虑 dsu 深度最多 log⁡n\log nlogn,开 10510^5105 个平衡树,每个平衡树最多只有 log⁡n\log nlogn 个点,我们只需要维护一个大小为 nlog⁡n=2×106n\log n=2\times 10^6nlogn=2×106 的平衡树即可。

时间复杂度 O(nlog⁡nlog⁡n)O(n\log n \log n)O(nlognlogn)

调了一个小时才A,真的蚌埠住了

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7, maxm = 1e7 + 7, INF = 0x3f3f3f3f;ll ans;
int val[maxn];
int root[maxn];
int deep[maxn];namespace treap
{ struct node{int l, r; int key; int val; int cnt; int size; }tr[maxm];int root, idx;void pushup(int p){tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + tr[p].cnt;}int get_node(int key){tr[ ++ idx].key = key;tr[idx].val = rand(); tr[idx].cnt = tr[idx].size = 1;return idx;}void zig(int &p){//右旋int q = tr[p].l;tr[p].l = tr[q].r;tr[q].r = p, p = q;pushup(tr[p].r), pushup(p);}void zag(int &p){//左旋int q = tr[p].r;tr[p].r = tr[q].l;tr[q].l = p, p = q;pushup(tr[p].l), pushup(p);}void my_insert(int &p, int key){if(!p) p = get_node(key); else if(tr[p].key == key) tr[p].cnt ++ ;else if(tr[p].key > key){ my_insert(tr[p].l, key);if(tr[tr[p].l].val > tr[p].val)zig(p);}else { my_insert(tr[p].r, key);if(tr[tr[p].r].val > tr[p].val) zag(p);}pushup(p);}void my_delet_one(int &p, int key){ if(!p) return ;if(tr[p].key == key){ if(tr[p].cnt > 1) tr[p].cnt -- ;else if(tr[p].l || tr[p].r){if(!tr[p].r || tr[tr[p].l].val > tr[tr[p].r].val){ zig(p);my_delet_one(tr[p].r, key);}else {zag(p);my_delet_one(tr[p].l, key);}}else p = 0; }else if(tr[p].key > key) my_delet_one(tr[p].l, key); else my_delet_one(tr[p].r, key); pushup(p); }int get_rank_by_key(int p, int key){if(!p) return 0;if(tr[p].key == key) return tr[tr[p].l].size + tr[p].cnt;if(tr[p].key > key)return get_rank_by_key(tr[p].l, key);return tr[tr[p].l].size + tr[p].cnt + get_rank_by_key(tr[p].r, key);}int get_key_by_rank(int p, int rank){if(!p) return 0;if(tr[tr[p].l].size >= rank) return get_key_by_rank(tr[p].l, rank);if(tr[tr[p].l].size + tr[p].cnt > rank) return tr[p].key;return get_key_by_rank(tr[p].r, rank - tr[tr[p].l].size - tr[p].cnt);  }
}int n, m, s, t, k;
int head[maxn], ver[maxn << 1], edge[maxn << 1], nex[maxn << 1], tot;
int siz[maxn], h_son[maxn];
int p[maxn];void add(int x, int y)
{ver[tot] = y;nex[tot] = head[x];head[x] = tot ++ ;
}void cal(int x, int z, int depth)
{int vy = 2 * val[z] - val[x];int maxdepth = min(n, k - deep[x] + 2 * depth);if(vy >= 0 && vy <= n && maxdepth >= 1) {int res = treap :: get_rank_by_key(root[vy], maxdepth); ans += res;}for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];cal(y, z, depth);}
}void add_node(int x, int z)
{treap :: my_insert(root[val[x]], deep[x]);for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];add_node(y, z);}
}void delet_node(int x)
{treap :: my_delet_one(root[val[x]], deep[x]);for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];delet_node(y);}
}void dfs1(int x, int fa)
{siz[x] = 1;int h_son_siz = -1, son = -1;for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];if(y == fa) continue;deep[y] = deep[x] + 1;dfs1(y, x);siz[x] += siz[y];if(siz[y] > h_son_siz) {h_son_siz = siz[y], son = y;}}if(son != -1)h_son[x] = son;
}void dsu_on_tree(int x, int fa)
{for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];if(y != h_son[x]) {dsu_on_tree(y, x);delet_node(y);}}if(h_son[x])dsu_on_tree(h_son[x], x); for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];if(y != h_son[x]) {cal(y, x, deep[x]);add_node(y, x);}}treap :: my_insert(root[val[x]], deep[x]);
}int main()
{memset(head, -1, sizeof head); scanf("%d%d", &n, &k);for (int i = 1; i <= n; ++ i)scanf("%d", &val[i]);for (int i = 2; i <= n; ++ i) {int u;scanf("%d", &u);add(u, i);//, add(i, u);}deep[1] = 1;dfs1(1, -1);dsu_on_tree(1, -1);printf("%lld\n", ans * 2);return 0;
}

2019 ICPC 南昌 K. Tree(树上启发式合并,平衡树 treap)相关推荐

  1. 2019 ICPC Asia Nanchang Regional K.Tree 树上启发式合并 + 动态开点线段树

    传送门 文章目录 题意: 思路: 题意: 给你一棵树,每个点都有一个权值valvalval,求满足以下条件 (1)x!=yx!=yx!=y (2)xxx和yyy不互为祖先 (3)val[lca(x,y ...

  2. 中石油训练赛 - Russian Dolls on the Christmas Tree(树上启发式合并/主席树)

    题目链接:点击查看 题目大意:给出一棵 n 个节点的树,以点 1 为根,现在对于每个节点作为根的子树求解:子树中有多少个编号不相交的连续子段,如:1 2 4 5 7,共有三个连续的段,分别为 [ 1 ...

  3. 山东理工大学第十二届ACM程序设计竞赛 - Cut the tree(树上启发式合并+线段树)

    题目链接:点击查看 题目大意:给一个具有 N 个节点的有根树,以 1 号节点为根,节点编号从 1 开始,点有点权.树的第 H 层权值为深度为 H 的所有点的点权之和.树的总权值为所有层权值的最大值.问 ...

  4. [dsu on tree]树上启发式合并总结(算法思想及模板附例题练习)

    文章目录 前言 树上启发式合并 引入 算法思想 时间复杂度 模板 练习 例题:CF600E Lomsat gelral solution code CF208E Blood Cousins solut ...

  5. 树上启发式合并问题 ---- 2019icpc南昌 K. Tree (树上启发式合并 + 动态开点线段树)

    题目链接 题目大意: 就是给你一颗树,每个点有个权值viv_ivi​,问你有多少对(x,y)(x,y)(x,y)满足: xxx不是yyy的祖先 yyy也不是xxx的祖先 xxx和yyy的距离不超过kk ...

  6. 树上启发式合并问题 ---- D. Tree and Queries[树上启发式合并+树状数组]

    题目链接 题目大意: 就是给你一棵树,树上每个节点都有一个颜色,在你mmm次询问每次询问给你一个节点uuu和一个数字kkk,问你在uuu这颗子树里面又少种颜色的结点个数是大于kkk; 解题思路: 看到 ...

  7. (树上启发式合并)CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://www.luogu.com.cn/problem/CF741D Pro ...

  8. CodeForces - 375D Tree and Queries(树上启发式合并)

    题目链接:点击查看 题目大意:给出一棵有根树,每个节点都有一个编号代表颜色,现在给出m个询问,每个询问的形式为u k,需要回答以u为根节点的子树中,数量超过k的颜色有多少种 题目分析:树上启发式合并模 ...

  9. 【CF 600E】Lomsat gelral(树上启发式合并, dsu on tree, 静态链分治,模板题)

    Algorithm 名称:树上启发式合并, dsu on tree, 静态链分治 用处:一般用来解决一类不带修改的子树查询问题 核心思想为:利用重链剖分的性质优化子树贡献的计算. 前置知识:启发式合并 ...

最新文章

  1. MaxReceivedMessageSize :已超过传入消息(65536)的最大消息大小配额
  2. 录屏、直播中的鼠标键盘演示神器PointFocus
  3. 最小错误率贝叶斯决策的基本思想_太赞了!机器学习基础核心算法:贝叶斯分类!(附西瓜书案例及代码实现)...
  4. ajax post 请求415\ 400 错误
  5. html5文字飞入插件,jquery使用CSS3实现文字动画效果插件Textillate.js
  6. C#session共享+redis_技术干货分享:基于SpringBoot+Redis的Session共享与单点登录
  7. linux命令中tar后跟的zxvf是什么意思
  8. 基于Hadoop2.2.0版本号分布式云盘的设计与实现
  9. vue组件通信之父子组件通信
  10. python读取文本数据--完善中
  11. 【泛型高级-通配符】
  12. 深度装机大师一键重装_深度装机大师一键重装软件
  13. 公有云与私有云的概念解读与优势分析
  14. 生物类似药带量采购将至?互换性问题尚未达成一致,专家评议:难度很大,需要慎重-1
  15. 智能电视硬件架构设计——整机研发
  16. docker:配置 Docker 加速器
  17. Android OTA在线升级一(架构分析)
  18. BP神经网络原理及在Matlab中的应用
  19. 解决 C2449在文件范围内找到 “{“(是否缺少函数头?), C2059 语法错误:“}“, C1075 “{“:未找到匹配令牌问题
  20. 音频 ----- DRC

热门文章

  1. 数字图像基本处理算法小结
  2. 实战:使用 PyTorch 和 OpenCV 实现实时目标检测系统
  3. 树莓派安装openCV做图像识别
  4. 收藏 | 深度学习中神经网络的可视化解释!
  5. 任正非公开信深度解读:两年怎样改变了华为?
  6. Apache 基金会发布2018财年年报:Java 项目占大半
  7. .Net+SQL Server企业应用性能优化笔记3——SQL查询语句
  8. JQuery 1.32 DatePicker 增强版
  9. 用友ERP供应链模块(一)----库存盘点
  10. 入门月薪8k,3年经验年薪30w,大数据薪酬待遇竟这么高?