能够解决的题目类型

这个 Trick 能解决的题目形如:

  • 给定 \(n\) 个节点的有根无边权有点权树。
  • 有 \(m\) 个询问,每个询问形如点 \(x\) 的子树内与 \(x\) 深度差不超过 \(k\) 的点的极值/排名/和。
  • \(O(n\,log\,n)\) 可过。

优缺点

优点:可以强制在线,代码简单。

缺点:可能被卡常(概率非常小)。

思路

首先,深度差不超过 \(k\) 这个限制很难办,我们无法用一维的编号把这些点串起来,而且没有什么差分方法。

那么——二维,启动!

我们把一个数点 \(x\) 变成二维平面上的点:\((depp_x\,,dfn_x)\)。

那么对于一个点 \(p\) 的询问就变成了横坐标在 \([depp_p\,,depp_p+k]\) 中,纵坐标在 \([dfn_p\,,dfn_p+sz_p-1]\) 的点的极值/排名/和。

这个显然可以用树套树,但是 \(O(n\,log^2\,n)\),有没有更优的方法呢?

我们考虑主席树,但是主席树必须满足可减性,而最值没有。

但是,当一个点的横坐标在属于 \([1,depp_p-1]\) 时,他的纵坐标一定不属于 \([depp_p\,,dep_p+k]\),也就是说我们并不需要将两颗线段树相减,那么询问也就不用讲满足可减性。

所以我们就可以愉快地切题了。

算法流程

  1. 用一个 dfs 求出每个节点的 \(dfn,sz,depp\)。
  2. 把节点按照深度排序,一个一个加入主席树,并记录对于每个深度的最后一课主席树的根的下标 \(idx\)。

例题代码

本 Trick 的代码基本每道题没什么变化,直接套用就行了

CF893F Subtree Minimum Query

#include <bits/stdc++.h>
using namespace std; #define midd ((node[u].l + node[u].r) >> 1)
constexpr int maxn = 100010; int n, r, m, v[maxn], a, b, dfn[maxn], nowdfn, depp[maxn], s[maxn], idx[maxn], sz[maxn], lans, maxdep = 0;
vector <int> G[maxn]; struct nodee {
int v, l, r, ls, rs;
} ;
struct tr {
nodee node[maxn << 5];
int root[maxn], cnt;
void build(int &u, int l, int r) {
u = ++cnt;
node[u] = {1000000000, l, r, 0, 0};
if (l == r) return ;
build(node[u].ls, l, midd);
build(node[u].rs, midd + 1, r);
return ;
}
void update(int &u, int pree, int x, int k) {
u = ++cnt;
node[u] = node[pree];
node[u].v = min(node[u].v, k);
if (node[u].l == node[u].r) return ;
if (x <= midd) update(node[u].ls, node[pree].ls, x, k);
else update(node[u].rs, node[pree].rs, x, k);
return ;
}
int query(int u, int l, int r) {
if (node[u].l >= l && node[u].r <= r) return node[u].v;
int ress = 1000000000;
if (l <= midd) ress = min(query(node[u].ls, l, r), ress);
if (r > midd) ress = min(query(node[u].rs, l, r), ress);
return ress;
}
} t; void dfs(int u, int fa) {
sz[u] = 1;
dfn[u] = ++nowdfn;
for (int now : G[u]) {
if (now == fa) continue;
depp[now] = depp[u] + 1;
maxdep = max(maxdep, depp[now]);
dfs(now, u);
sz[u] += sz[now];
}
return ;
} signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); cin >> n >> r;
depp[r] = 1;
for (int i = 1; i <= n; i++) {
s[i] = i;
cin >> v[i];
}
for (int i = 1; i < n; i++) {
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
dfs(r, 0);
sort(s + 1, s + 1 + n, [](int a, int b){return depp[a] < depp[b];});
// 以上为第一部分 dfs
t.build(t.root[0], 1, n);
idx[0] = t.root[0];
for (int i = 1; i <= n; i++) {
t.update(t.root[i], t.root[i - 1], dfn[s[i]], v[s[i]]);
if (depp[s[i]] != depp[s[i + 1]]) idx[depp[s[i]]] = i;
}
// 以上为第二部分 主席树预处理
cin >> m;
while (m--) {
cin >> a >> b;
a = (a + lans) % n + 1;
b = (b + lans) % n;
lans = t.query(t.root[idx[min(maxdep, depp[a] + b)]], dfn[a], dfn[a] + sz[a] - 1);
cout << lans << '\n';
} return 0;
}

数据结构 Trick 之:子树 k 距离内问题的更多相关文章

  1. 【LeetCode】358.K 距离间隔重排字符串

    358.K 距离间隔重排字符串 知识点:哈希表:贪心:堆:队列 题目描述 给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少 ...

  2. OpenJudge数据结构与算法-计算点的距离并排序

    /*================================================================== 距离排序 总时间限制: 1000ms 内存限制: 65536k ...

  3. 排序算法 以及HKU的一些数据结构 相关题目 以及 K叉树,二叉树 排列

    冒泡排序.选择排序.快速排序.插入排序.希尔排序.归并排序.基数排序以及堆排序,桶排序 https://www.cnblogs.com/Glory-D/p/7884525.html https://b ...

  4. [Leetcode 787]中转K站内最便宜机票

    题目 n个城市,想求从src到dist的最廉价机票 有中转站数K的限制,即如果k=5,中转10次机票1000,中转5次机票2000,最后返回2000 There are n cities connec ...

  5. Laravel 框架根据经纬度计算在一定距离内的数据

    $model = DB::table('table_name'); public static function scope_distance($model, $from_latitude, $fro ...

  6. HDU 4347 - The Closest M Points - [KDTree模板题]

    本文参考: https://www.cnblogs.com/GerynOhenz/p/8727415.html kuangbin的ACM模板(新) 题目链接:http://acm.hdu.edu.cn ...

  7. LA3902 Network

    给出一棵树,对于每一个叶子节点要使得在它的k距离内至少一个节点被打了标记,(叶节点不能打标记,非叶结点也不必满足这个条件),现在已经有一个节点s被打了标记,问至少还要打几个标记(这表达能力也是捉急.. ...

  8. Leetcode——863.二叉树中所有距离为 K 的结点

    给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 K . 返回到目标结点 target 距离为 K 的所有结点的值的列表. 答案可以以任何顺序返回. 示例 1: 输 ...

  9. php mysql 计算经纬之间距离 范围内筛选

    <?php /** * 根据经纬度和半径计算出范围 * @param string $lat 纬度 * @param String $lng 经度 * @param float $radius ...

  10. 常用查找数据结构及算法(Python实现)

    目录 一.基本概念 二.无序表查找 三.有序表查找 3.1 二分查找(Binary Search) 3.2 插值查找 3.3 斐波那契查找 四.线性索引查找 4.1 稠密索引 4.2 分块索引 4.3 ...

随机推荐

  1. 2023年10月,红米(小米)note 8 pro 优化记

    看了红米的note 13 pro和note 12 turbo的参数和价格后,我决定下单买个note8 pro的手机壳,确实有新手机的感觉了. 我note8 pro手机参数如下 MIUI 12.0.5 ...

  2. Codeforces Round 975 Div.2 C题 解析

    C题 题目链接:Problem - C - Codeforces 题目描述 思路 对于这道题,首先我们能想到最小的组数肯定是数量最多的那个卡片的数量(mx),因为这个值的每一个卡片不能在同一个组里面. ...

  3. 鸿蒙开发Hvigor任务简介

    编译构建工具DevEco Hvigor(以下简称Hvigor)是一款基于TS实现的构建任务编排工具,主要提供任务管理机制,包括任务注册编排.工程模型管理.配置管理等关键能力,提供专用于构建和测试应用的 ...

  4. ARC143D Bridges

    ARC143D Bridges 巧妙的图论题. 思路 分析题目,发现很像拆点. 由于拆点要设置出入点,这里我们也把 \(a_i\) 设成入点,把 \(a_i+n\) 设成出点,再次分析问题. 考虑我们 ...

  5. 2.TP6的入门-分页类的改写

    看了看推荐的分页类的使用,还是很简单的,可是自己去尝试改写生成的分页类结构就会很麻烦,总是不成功,后来发现手册里面还有这个 就说你想重写分页类,就需要这样做 赶紧实践了一下,先改这里的provider ...

  6. 腾讯AICR : 智能化代码评审技术探索与应用实践(下)

  7. 使用 ASM 实现 Java 语言的“多重继承”

    问题的提出 在大部分情况下,需要多重继承往往意味着糟糕的设计.但在处理一些遗留项目的时候,多重继承可能是我们能做出的选择中代价最小的.由于 Java 语言本身不支持多重继承,这常常会给我们带来麻烦,最 ...

  8. Java 10大优点—Part4—Java内存模型

    本文由 ImportNew - 靳禹 翻译自 zeroturnaround.如需转载本文,请先参见文章末尾处的转载要求. 在忙着参加在爱沙尼亚进行的 TEDx talk 演讲活动以及在比利时举办的一届 ...

  9. 一套以用户体验出发的.NET8 Web开源框架

    前言 今天大姚给大家分享一套以用户体验出发的.NET8 Web开源框架:YiFramework. 项目介绍 YiFramework是一个基于.NET8 + Abp.vNext + SqlSugar 的 ...

  10. vue3笔记

    如何创建vue3项目 基于 vue 脚手架 npm i @vue/cli -g vue create <project-name> cd <project-name> npm ...