P10604 BZOJ4317 Atm 的树 题解

news/2024/7/6 6:43:35/文章来源:https://www.cnblogs.com/Athanasy/p/18282816

题目链接:P10604 BZOJ4317 Atm 的树

简单点分树题。我们考虑第 \(k\) 大问题常见的两种做法:

  1. 树上二分。

  2. 二分 \(+\) check。

显然这题由于有若干个点对应的路径关系,并不太好用前者,我们不可能为某个点经过的所有路径都建立一棵权值线段树,然后再权值线段树上二分,因为路径总数是 \(O(n^2)\) 的。

考虑第二种,我们二分 \(k\) 路径长:

我们对于大型路径问题常见的方式就是 点分治 或者 点分树 来做。这题由于我们使用点分树来做:

对于点分树来说:

  1. 某个分治中心将会在它的后代分治中心消失,所以包含该分治中心的点的时间仅仅只有从该点到所有祖先分治中心节点的每个分治中心所在的时间树,树高为 \(O(\log{n})\),暴力访问即为 \(O(\log{n})\)。本质上分治中心可以看做该树在某一时间下的时间树,特征为以该分治中心作为根,其祖先分治中心方向的子树全部消失

  2. 对于每个分治中心的贡献路径,当且仅当该路径包含该分治中心,我们常见的把路径分为两类:
    (1) 以该分治中心作为端点进行衍生。
    (2) 以该分治中心作为分割点,从任意两棵不相同的子树中任取两个点作为端点,拼接而成的路径。

  3. 枚举祖先分治中心,基于点 \(2\) ,考虑同时经过当前点和该分治中心的点的路径即为该分治中心对当前这个点作为分治中心的贡献。

常见的点分树维护:

  1. 维护以某个点作为根即分治中心的所有链信息。

  2. 维护某个分治中心的父分治中心到该分治中心方向上的链信息。

通过 \(1\) 去掉 \(2\),即为除了当前子树以外的其他子树的链信息。

回到本题

考虑我们即为寻找所有经过当前查询点的路径中,\(\le mid\) 的数目,判断是否 \(\ge k\) 即为 \(check\)。那么最好的方式显然可以考虑随便维护一个权值数据结构,这边直接使用了:动态开点树状数组

考虑查询,对于一个 \(fa\) 与当前点的贡献,显然我们可以使用树上前缀和处理出二者之间的路径 \(d\),然后查询 \(\le mid-d\) 的数目,即可查询到该分治中心的贡献,这个可以用上述点分树维护的容斥思路算出,注意 \(d\) 也是一个答案,当然你可以可以考虑维护 \(0\) 这条空链,但要注意去掉,我自然是暴力判断 \(d\) 了。二分的话,上界为 \(wn\),而 \(w\) 又比较小,所以这样一来单点查询的复杂度显然就是 \(O(\log^3{n})\)

参照代码
#include <bits/stdc++.h>// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")#define isPbdsFile#ifdef isPbdsFile#include <bits/extc++.h>#else#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope>#endifusing namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};template <typename T>
int disc(T* a, int n)
{return unique(a + 1, a + n + 1) - (a + 1);
}template <typename T>
T lowBit(T x)
{return x & -x;
}template <typename T>
T Rand(T l, T r)
{static mt19937 Rand(time(nullptr));uniform_int_distribution<T> dis(l, r);return dis(Rand);
}template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{return (a % b + b) % b;
}template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{a %= c;T1 ans = 1;for (; b; b >>= 1, (a *= a) %= c) if (b & 1) (ans *= a) %= c;return modt(ans, c);
}template <typename T>
void read(T& x)
{x = 0;T sign = 1;char ch = getchar();while (!isdigit(ch)){if (ch == '-') sign = -1;ch = getchar();}while (isdigit(ch)){x = (x << 3) + (x << 1) + (ch ^ 48);ch = getchar();}x *= sign;
}template <typename T, typename... U>
void read(T& x, U&... y)
{read(x);read(y...);
}template <typename T>
void write(T x)
{if (typeid(x) == typeid(char)) return;if (x < 0) x = -x, putchar('-');if (x > 9) write(x / 10);putchar(x % 10 ^ 48);
}template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{write(x), putchar(c);write(c, y...);
}template <typename T11, typename T22, typename T33>
struct T3
{T11 one;T22 tow;T33 three;bool operator<(const T3 other) const{if (one == other.one){if (tow == other.tow) return three < other.three;return tow < other.tow;}return one < other.one;}T3(){one = tow = three = 0;}T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three){}
};template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{if (x < y) x = y;
}template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{if (x > y) x = y;
}struct Hash
{static uint64_t splitmix64(uint64_t x){x += 0x9e3779b97f4a7c15;x = (x ^ x >> 30) * 0xbf58476d1ce4e5b9;x = (x ^ x >> 27) * 0x94d049bb133111eb;return x ^ x >> 31;}static size_t get(const uint64_t x){static const uint64_t FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();return splitmix64(x + FIXED_RANDOM);}template <typename T>size_t operator()(T x) const{return get(std::hash<T>()(x));}template <typename F, typename S>size_t operator()(pair<F, S> p) const{return get(std::hash<F>()(p.first)) ^ std::hash<S>()(p.second);}
};constexpr int N = 1e5 + 10;
constexpr int T = log2(N) + 1;
constexpr int MX = 150000;
vector<pii> child[N];
int n, k;struct
{int fa[N][T + 1], deep[N], pre[N];void dfs(const int curr, const int pa){deep[curr] = deep[fa[curr][0] = pa] + 1;forn(i, 1, T) fa[curr][i] = fa[fa[curr][i - 1]][i - 1];for (const auto [nxt,val] : child[curr]){if (nxt != pa) pre[nxt] = pre[curr] + val, dfs(nxt, curr);}}int LCA(int x, int y) const{if (deep[x] < deep[y]) swap(x, y);forv(i, T, 0) if (deep[fa[x][i]] >= deep[y]) x = fa[x][i];if (x == y) return x;forv(i, T, 0) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];return fa[x][0];}int dist(const int x, const int y) const{return pre[x] + pre[y] - 2 * pre[LCA(x, y)];}
} LCA;struct
{hash2<int, int, Hash> bit[N];void add(const int root, int x){while (x <= MX) bit[root][x]++, x += lowBit(x);}int query(const int root, int x){int ans = 0;while (x){if (bit[root].find(x) != bit[root].end()) ans += bit[root][x];x -= lowBit(x);}return ans;}
} cnt, cntFa;struct
{bool del[N];int sumSize, maxSon, root;int siz[N], dist[N][T + 1], fa[N], deep[N];void makeRoot(const int curr, const int pa){siz[curr] = 1;int currSize = 0;for (const auto nxt : child[curr] | views::keys){if (del[nxt] or nxt == pa) continue;makeRoot(nxt, curr);siz[curr] += siz[nxt];uMax(currSize, siz[nxt]);}uMax(currSize, sumSize - siz[curr]);if (currSize < maxSon) maxSon = currSize, root = curr;}void dfs(const int curr, const int pa){siz[curr] = 1;for (const int nxt : child[curr] | views::keys){if (!del[nxt] and nxt != pa) dfs(nxt, curr), siz[curr] += siz[nxt];}}void buildCurr(const int curr, const int v, const int rt, const int pa){for (const auto [nxt,val] : child[curr]){if (del[nxt] or nxt == pa) continue;cnt.add(rt, v + val);buildCurr(nxt, v + val, rt, curr);}}void buildFa(const int curr, const int v, const int rt, const int pa){cntFa.add(rt, v);for (const auto [nxt,val] : child[curr]){if (del[nxt] or nxt == pa) continue;buildFa(nxt, v + val, rt, curr);}}void build(const int curr){del[curr] = true;buildCurr(curr, 0, curr, 0);for (const auto [nxt,val] : child[curr]){if (del[nxt]) continue;sumSize = maxSon = siz[nxt];makeRoot(nxt, 0);dfs(root, 0);buildFa(nxt, val, root, curr);deep[root] = deep[fa[root] = curr] + 1;build(root);}}void init(){LCA.dfs(1, 0);sumSize = maxSon = n;makeRoot(1, 0);build(root);forn(son, 1, n){for (int rt = fa[son]; rt; rt = fa[rt]) dist[son][deep[son] - deep[rt]] = LCA.dist(son, rt);}}bool check(const int curr, const int len) const{int ans = cnt.query(curr, len);for (int nxt = curr; fa[nxt]; nxt = fa[nxt]){const int d = dist[curr][deep[curr] - deep[fa[nxt]]];if (len >= d){ans++;ans += cnt.query(fa[nxt], len - d);ans -= cntFa.query(nxt, len - d);}}return ans >= k;}int query(const int curr) const{int l = 1, r = MX;while (l < r){const int mid = l + r >> 1;if (check(curr, mid)) r = mid;else l = mid + 1;}return l;}
} pointTree;inline void solve()
{cin >> n >> k;forn(i, 1, n-1){int u, v, val;cin >> u >> v >> val;child[u].emplace_back(v, val);child[v].emplace_back(u, val);}pointTree.init();forn(i, 1, n) cout << pointTree.query(i) << endl;
}signed int main()
{// MyFileSpider//------------------------------------------------------// clock_t start = clock();int test = 1;//    read(test);// cin >> test;forn(i, 1, test) solve();//    while (cin >> n, n)solve();//    while (cin >> test)solve();// clock_t end = clock();// cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
}

\[预处理倍增数组:\ O(n\log{n}) \]

\[构建点分树:\ O(n\log{n}) \]

\[预处理两个容斥树状数组:\ O(n\log^2{n}) \]

\[预处理每个分治到祖先分治中心的距离数组:\ O(n\log^2{n}) \]

\[单点查询:\ 二分+点分树上暴力跳祖先分治中心+树状数组容斥查询=O(\log^3{n}) \]

\[所以总复杂度为:\ O(n\log^3{n}) \]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/737136.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不同网站检测到的ip不同

背景 最近在使用某个接口时出现了问题,大致是根据ip查询地址。 于是使用查询ip的网站,发现ip各有不同。大致上是有三种ip。 探讨 经过查询,比较合理的解释是,运营商有多个网络出口,根据访问的网站不同,使用的网络出口也不同,因此不同的网站分别使用了不同的ip去访问,因…

全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器:把方法包装成属性

本文主要对@property 装饰器的基本定义、使用场景和使用方法进行了介绍,同时介绍了setter装饰器和deleter装饰器的应用场景和语法。全网最适合入门的面向对象编程教程:08 类和对象的 Python 实现-@property 装饰器:把方法包装成属性 摘要: 本文主要对@property 装饰器的基本…

Java 异常 随机数 包装类

异常,随机数,包装类,日期类正如 “人无完人”一样,程序也不是完美的,它总会存在这样那样的问题,而有些问题并不是能够通过程序员开发更好的代码来解决的,如果我们忽视它,可能就会造成程序的终止,甚至是系统的崩溃。因此,我们需要想办法来合理的解决它,这就是Java中异常…

DataWhale暑期夏令营第一期——大模型技术方向task2笔记

Task 2 笔记 数据分析 可以先通过对标签中各个项进行数据分析(使用values_count方法),可以得到主要任务的各个指标的值分布情况。 我认为这一步的作用:帮助理解数据。 大模型的本质还是概率生成,通过prompt提示词去进行生成Baseline优化思路 1.数据处理角色合并:将同一个…

基于Bootstrap Blazor开源的.NET通用后台权限管理系统

前言 今天大姚给大家分享一个基于Bootstrap Blazor开源的.NET通用后台权限管理系统,后台管理页面兼容所有主流浏览器,完全响应式布局(支持电脑、平板、手机等所有主流设备),可切换至 Blazor 多 Tabs 模式,权限控制细化到网页内任意元素(按钮、表格、文本框等等):Boots…

03-立即执行函数

JS中的立即执行函数01 立即执行函数的定义 立即执行函数有自己的作用域,因此可以防止全局变量之间的污染02 应用场景 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible…

初体验Sonar10.6 之 从部署到实战

Sonar介绍及下载 Sonar是一个代码质量管理的开源平台,用于管理源代码的质量。 SonarLint IDE插件安装 https://plugins.jetbrains.com/plugin/7973-sonarlint https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarlint-vscode sonar scanner下载地址 http…

charles使用

一,下载 去官网下载charles,如果有破解版的更好,不用花钱,但是一般也有30天试用期 二,安装 按照步骤安装即可 三,使用 1,首先,安装本地证书。按照指引一步一步安装。(注意:保存的时候最好放到受信任的证书目录中)2,安装移动端证书:它会告诉你ip和port。 首先你需要…

算法金 | 致敬深度学习三巨头:不愧是腾讯,LeNet问的巨细。。。

​大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」抱个拳,送个礼 读者参加面试,竟然在 LeNet 这个基础算法上被吊打~ LeNet 确实经典,值得好好说道说道 更多内容,见微*公号往期文章:有史以来最详细的卷积神经网络…

[大疆航线] 系列(3) 无人机多角度航线规划软件μMAPLE

关键词:无人机航线、航点动作,航线软件 作者:ludwig1860 日期:2024.7.3 1. 多角度航线规划软件μMAPLE的编写 我们研究团队编写了一个名为μMAPLE (uav-based Multi-Angular flight PLannEr)的多角度航线规划软件。当然,我们也很乐意协助研究人员们开发符合各自需求的航线…

Windows Terminal 中设置常用命令的别名

Windows Terminal 中设置常用命令的别名 ‍ E:\zhpj\Desktop>cmd /? 启动 Windows 命令解释器的一个新实例 . . . 如果 /D 未在命令行上被指定,当 CMD.EXE 开始时,它会寻找 以下 REG_SZ/REG_EXPAND_SZ 注册表变量。如果其中一个或 两个都存在,这两个变量会先被执行。HKE…

ssrf结合python反序列化

存储session对象时 当然不能直接存储对象 需要转换成有规律的字符串 这一过程就涉及到了序列化 将对象转换成字符串这一过程称之为序列化 PYTHON反序列化漏洞 本文中就涉及到了pickle这一序列化模块导致的反序列化漏洞 在反序列化结束时 会触发__reduce__魔术方法 类似于php中的…

Web基础知识扫盲

1、中间件 定义:中间件是一种独立的系统软件服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源,中间件位于客户机服务器的操作系统之上,管理计算资源和网络通信。常见的中间件:IIS、Apache、Nginx、Tomcat 2、NAT网络地址转换 这里只介绍动态转换一种 动态转换…

MySQL-16.MVCC(多版本并发控制)

C-16.多版本并发控制 1.什么是MVCCMVCC(Multiversion Concurrency Control),多版本并发控制。顾名思义,MVCC是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换言之,就是为了查询一些正在被另一事务更…

[JLU] 数据结构与算法上机题解思路分享-课程设计第一次与第二次上机

这是吉林等通知大学数据结构与算法上机题的题解思路,没有精妙的解法,只是一个记录罢前言 首先,请务必自己尽全力尝试实现题目,直接看成品代码,思维就被拘束了,也很容易被查重。 这里只是思路解析的博客,代码仓库在 JLU_Data_Structures_Record 希望你能在这里找到你想要…

【Python】GUI开发笔记

一、环境搭建: 1、Pycharm开发工具pycharm历史版本 https://www.jetbrains.com/pycharm/download/other.html破解插件 https://blog.csdn.net/weixin_50737119/article/details/135628513 2、PYENV 版本管理 Python也有对应的版本管理工具,叫pyenv 这个东西挺奇怪的,直接发…

Day1| 704. 二分查找 27. 移除元素

704.二分查找 题目链接 : https://leetcode.cn/problems/binary-search/description/ 思路😗*切记二分查找要基于排序好的数组或者数据,否则二分查找必不能使用!!!!!!!!! ** 双指针写最简单,一个头指针从0开始,一个尾指针从数组长度-1开始,中间指针是头+尾/2,每次比较头尾中间…

不同操作系统下的换行符

1. 关键字 2. 换行符的比较 3. ASCII码 4. 修改换行符4.1. VSCode5. 参考文档1. 关键字 CR LF CRLF 换行符 2. 换行符的比较英文全称 英文缩写 中文含义 转义字符 ASCII码值 操作系统Carriage Return CR 回车 \r 13 MacIntosh(早期的Mac)Linefeed LF 换行/新行 \n 10 Unix/Li…

1s内控制向某个请求请求的次数

背景 有的时候后端提供的接口对相同的IP进行限制,在某个时间内不能发送超过X条的请求,一旦超过指定的请求数会导致后续请求接口会出现异常。 效果需求 比如:在1s内最多同时发送2个请求,多出来的请求在后续的1s或者后续的Ns中发起 代码 <template><div class="…

电脑hold escape key to prevent startlsback怎么处理?

电脑出现hold escape key to prevent StartlsBack from,一般遇到这种问题之后,一直按住ESC键就没有了。但是还需彻底的解决掉这个问题。 首先我们按下“ctrl +alt +del”组合键打开任务管理器,左上角“运行新任务”,输入“control”并确定,就可以打开控制面板,查看方式为…