总结-DSU ON TREE(树上启发式合并)
考试遇到一道题:
有一棵n个点的有根树,每个点有一个颜色,每次询问给定一个点\(u\)和一个数\(k\),询问\(u\)子是多少个不同颜色节点的\(k\)级祖先。n<=500000。
显然对每一层建主席树可行,但还有更优雅的一种做法——\(DSU\)
所谓\(DSU\),是一类处理子树信息的问题的通解(\(O(n\log n\))
其主要过程是树剖后,沿重儿子向下,优先统计轻儿子,并在统计结束后删除对轻儿子统计信息,最后删除对重儿子统计信息。
参考代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <numeric>
#define R(a,b,c) for(register int a = (b); a <= (c); ++a)
#define nR(a,b,c) for(register int a = (b); a >= (c); --a)
#define Swap(a,b) ((a) ^= (b) ^= (a) ^= (b))
#define MP make_pair
#ifdef QWQ
#define D_e_Line printf("\n--------\n")
#define C_e(x) cout << (#x) << " : " << x << endl
#define D_e(x) cerr << (#x) << " : " << x << endl
#define Pause() system("pause")
#define FileOpen() freopen("in.txt", "r", stdin)
#define FileSave() freopen("out.txt", "w", stdout)
#include <assert.h>
#define TIME() fprint(stderr, "TIME : %.3lfms\n", (double)clock() / CLOCKS_PER_SEC)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#else
#define D_e_Line
#define D_e(x)
#define C_e(x)
#define Pause
#define FileOpen()
#define FileSave()
#define TIME()
#define dbg(...)
#endif
struct FastIO {
template<typename ATP> inline FastIO& operator >> (ATP &x) {
x = 0; int f = 1; char c;
for(c = getchar(); c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
while(c >= '0' && c <= '9') x = x * 10 + (c ^ '0'), c = getchar();
if(f == -1) x = -x;
return *this;
}
} io;
using namespace std;
template<typename ATP> inline ATP Max(ATP x, ATP y) {
return x > y ? x : y;
}
template<typename ATP> inline ATP Min(ATP x, ATP y) {
return x < y ? x : y;
}
template<typename ATP> inline ATP Abs(ATP x) {
return x < 0 ? -x : x;
}
#include <vector>
#include <set>
const int N = 1e5 + 7;
const int base = 122777;
char str[27];
inline unsigned long long HashVal(char *str) {
int len = strlen(str + 1);
unsigned long long s = 1;
R(i,1,len)
s = s * base + str[i] - 'a';
return s;
}
struct Edge {
int nxt, pre;
} e[N];
int head[N], cntEdge;
inline void add(int u, int v) {
e[++cntEdge] = (Edge){ head[u], v}, head[u] = cntEdge;
}
struct Ques {
int K, id;
Ques() {}
Ques(int _K, int _id) : K(_K), id(_id) {}
};
int ans[N];
vector<Ques> q[N];
set<int> tot[N];
unsigned long long val[N];
int son[N], dep[N], fa[N], siz[N];
inline void DFS_First(int u, int father) {
dep[u] = dep[father] + 1, fa[u] = father, siz[u] = 1;
for(register int i = head[u]; i; i = e[i].nxt){
int v = e[i].pre;
DFS_First(v, u);
siz[u] += siz[v];
if(!son[u] || siz[v] > siz[son[u]]) son[u] = v;
}
}
bool big[N];
inline void Clear(int u, int father) {
tot[dep[u]].clear();
for(register int i = head[u]; i; i = e[i].nxt){
int v = e[i].pre;
if(big[v]) continue; // if it' s a heavy son, ignore it
Clear(v, u);
}
}
inline void Calc(int u, int father) {
tot[dep[u]].insert(val[u]);
for(register int i = head[u]; i; i = e[i].nxt){
int v = e[i].pre;
if(big[v]) continue;
Calc(v, u);
}
}
int n;
inline void DSU(int u, int father, int flag) { // flag = 0 : light, 1 : heavy
for(register int i = head[u]; i; i = e[i].nxt){ // every light son
int v = e[i].pre;
if(v == son[u]) continue;
DSU(v, u, 0);
}
if(son[u]) DSU(son[u], u, 1), big[son[u]] = true; // heavy son
Calc(u, father);
for(vector<Ques>::iterator it = q[u].begin(); it != q[u].end(); ++it){
int t = dep[u] + it -> K;
if(t <= n + 1) ans[it -> id] = tot[t].size();
}
if(son[u]) big[son[u]] = false; // finished getting the information from the heavy son
if(!flag) Clear(u, father); // clear the information from the light son
}
int main() {
freopen("ancestor.in", "r", stdin);
freopen("ancestor.out", "w", stdout);
//FileOpen();
//FileSave();
io >> n;
R(i,1,n){
scanf("%s", str + 1);
val[i] = HashVal(str);
int fa;
io >> fa;
add(fa, i);
}
int Q;
io >> Q;
R(i,1,Q){
int x, K;
io >> x >> K;
q[x].push_back(Ques(K, i));
}
DFS_First(0, 0);
DSU(0, 0, 0);
R(i,1,Q){
printf("%d\n", ans[i]);
}
return 0;
}
/*
5
alice 0
alice 1
bob 2
cindy 1
bob 2
3
2 1
1 2
1 1
*/
例题
咕咕咕~
参考资料
总结-DSU ON TREE(树上启发式合并)的更多相关文章
- dsu on tree 树上启发式合并 学习笔记
近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...
- dsu on tree (树上启发式合并) 详解
一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...
- dsu on tree[树上启发式合并学习笔记]
dsu on tree 本质上是一个 启发式合并 复杂度 \(O(n\log n)\) 不支持修改 只能支持子树统计 不能支持链上统计- 先跑一遍树剖的dfs1 搞出来轻重儿子- 求每个节点的子树上有 ...
- dsu on tree(树上启发式合并)
简介 对于一颗静态树,O(nlogn)时间内处理子树的统计问题.是一种优雅的暴力. 算法思想 很显然,朴素做法下,对于每颗子树对其进行统计的时间复杂度是平方级别的.考虑对树进行一个重链剖分.虽然都基于 ...
- 树上启发式合并(dsu on tree)学习笔记
有丶难,学到自闭 参考的文章: zcysky:[学习笔记]dsu on tree Arpa:[Tutorial] Sack (dsu on tree) 先康一康模板题吧:CF 600E($Lomsat ...
- 【Luogu U41492】树上数颜色——树上启发式合并(dsu on tree)
(这题在洛谷主站居然搜不到--还是在百度上偶然看到的) 题目描述 给一棵根为1的树,每次询问子树颜色种类数 输入输出格式 输入格式: 第一行一个整数n,表示树的结点数 接下来n-1行,每行一条边 接下 ...
- 神奇的树上启发式合并 (dsu on tree)
参考资料 https://www.cnblogs.com/zhoushuyu/p/9069164.html https://www.cnblogs.com/candy99/p/dsuontree.ht ...
- CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths 树上启发式合并(DSU ON TREE)
题目描述 一棵根为\(1\) 的树,每条边上有一个字符(\(a-v\)共\(22\)种). 一条简单路径被称为\(Dokhtar-kosh\)当且仅当路径上的字符经过重新排序后可以变成一个回文串. 求 ...
- 树上启发式合并(dsu on tree)
树上启发式合并属于暴力的优化,复杂度O(nlogn) 主要解决的问题特点在于: 1.对于树上的某些信息进行查询 2.一般问题的解决不包含对树的修改,所有答案可以离线解决 算法思路:这类问题的特点在于父 ...
- hdu6191(树上启发式合并)
hdu6191 题意 给你一棵带点权的树,每次查询 \(u\) 和 \(x\) ,求以 \(u\) 为根结点的子树上的结点与 \(x\) 异或后最大的结果. 分析 看到子树,直接上树上启发式合并,看到 ...
随机推荐
- 【Azure 存储服务】Java Azure Storage SDK V12使用Endpoint连接Blob Service遇见 The Azure Storage endpoint url is malformed
问题描述 使用Azure Storage Account的共享访问签名(Share Access Signature) 生成的终结点,连接时遇见 The Azure Storage endpoint ...
- MASA Auth - SSO与Identity设计
AAAA AAAA即认证.授权.审计.账号(Authentication.Authorization.Audit.Account).在安全领域我们绕不开的两个问题: 授权过程可靠:让第三方程序能够访问 ...
- unittest框架里的常用断言方法:用于检查数据
1.unittest框架里的常用断言方法:用于检查数据. (1)assertEqual(x,y) 检查两个参数类型相同并且值相等.(2)assertTrue(x) 检查唯一的参数值等于True(3)a ...
- stm32f103ve+BH1750使用教程+oled(HAL库)
1.硬件:BH1750模块+oled 2.代码:BH1750是标准的iic协议的外设,我这里单独有iic的文件,之后想要实现多个设备共用一个iic. BH1750.c 1 #include " ...
- MAC NGINX PHP XDEBUG
1. 安装 homebrew 2. 安装nginx ; 终端运行 brew install nginx: 1)给nginx 设置管理员权限:如果不设置管理员权限,80端口是不能监听的: #这里的目录根 ...
- 谷歌浏览器Chrome官方下载地址
经常看到朋友的电脑上安装是魔改的谷歌浏览器.这里将谷歌浏览器官方的下载地址放在这里.有需要的朋友可以自己去下载. 下载地址 Chrome最新稳定在线安装版:https://www.google.cn/ ...
- SQL Server 2008~2019版本序列号/密钥/激活码 汇总
SQL Server 2019 Enterprise:HMWJ3-KY3J2-NMVD7-KG4JR-X2G8G Strandard:PMBDC-FXVM3-T777P-N4FY8-PKFF4 SQL ...
- TopoLVM: 基于LVM的Kubernetes本地持久化方案,容量感知,动态创建PV,轻松使用本地磁盘
正文 研发测试场景下,一般追求的是一键快速起环境,横向动态复制,一人一套,随起随用,用完即走.作为使用方,其不用关心实际的物理资源是怎样的,环境起在哪里,只要声明自己的使用需求即可.但作为方案构建者以 ...
- C# --- SqlserverHelper帮助类、快速实现增删改查
using System;using System.Data; using System.Data.SqlClient; namespace Demo.WorkerService { public c ...
- Tapdata 在线研讨会:如何快速上手 Tapdata Cloud?
偶然接触到 Tapdata Cloud,据说不仅可以实现异构数据实时同步,还永久 100% 免费,但就是不知道怎么获取.怎么用? 打开相关文档逐渐陷入迷茫,术语."黑话"随处可见, ...