参考资料

https://www.cnblogs.com/zhoushuyu/p/9069164.html

https://www.cnblogs.com/candy99/p/dsuontree.html

https://www.cnblogs.com/zcysky/p/6822395.html

简介

树上启发式合并

用到了heavy−light decomposition树链剖分

把轻边子树的信息合并到重链上的点里

因为每次都是先dfs轻儿子再dfs重儿子,只有重儿子子树的贡献保留,所以可以保证dfs到每颗子树时当前全局维护的信息不会有别的子树里的,和莫队很像

算法实现

1.遍历轻儿子

2.遍历重儿子(保留数据)

3.计算所有轻儿子为根的子树

4.如果当前点是轻儿子,清空影响

复杂度分析

树链剖分后每个点到根的路径上有\(logn\)条轻边和\(logn\)条重链

每个点遇见轻边时合并一次,所以至多\(logn\)次

总复杂度\(O(nlogn)\)

例题

CF600E. Lomsat gelral

http://codeforces.com/contest/600/problem/E

题意:询问每颗子树中出现次数最多的颜色们编号和

板子题

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 1e5+10;
int c[N], n;
struct node {
int to, nxt;
}g[N<<1];
int last[N], gl; void add(int x, int y) {
g[++gl] = (node) {y, last[x]};
last[x] = gl;
}
int son[N], siz[N];
void dfs1(int u, int f) {
siz[u] = 1;
for (int i = last[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (v == f) continue;
dfs1(v, u);
siz[u] += siz[v];
if (siz[son[u]] < siz[v]) son[u] = v;
}
return ;
} int num[N], top;
LL sum[N], ans[N];
bool vis[N]; void calc(int u, int fa, int k) {
sum[num[c[u]]] -= c[u];
num[c[u]] += k;
sum[num[c[u]]] += c[u];
if (sum[top + 1]) top++;
else if (!sum[top]) top--; for (int i = last[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (v == fa || vis[v]) continue;
calc(v, u, k);
}
return ;
} void dfs(int u, int fa, int op) {
for (int i = last[u]; i; i = g[i].nxt)
if (g[i].to != fa && g[i].to != son[u])
dfs(g[i].to, u, 0);
if (son[u])
dfs(son[u], u, 1), vis[son[u]] = 1;
calc(u, fa, 1); vis[son[u]] = 0;
ans[u] = sum[top];
if (!op) calc(u, fa, -1);
return ;
} int main() {
read(n);
for (int i = 1; i <= n; i++) read(c[i]);
for (int i = 1; i < n; i++) {
int x, y; read(x), read(y);
add(x, y), add(y, x);
}
dfs1(1, 0);
dfs(1, 0, 1);
for (int i = 1; i <= n; i++)
printf("%I64d ", ans[i]);
return 0;
}

CF570D Tree Requests

http://codeforces.com/problemset/problem/570/D

https://www.luogu.org/problemnew/show/CF570D

构成回文串,奇数个的字母至多一个

用二进制状压判断即可

\(sum[x]\)表示深度为\(x\)构成的状态

#include<bits/stdc++.h>

#define LL long long
#define RG register using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
} const int N = 500010; struct node {
int to, nxt;
}g[N<<1], q[N];
int last[N], gl;
int n, m;
void add(int x, int y) {
g[++gl] = (node) {y, last[x]};
last[x] = gl;
g[++gl] = (node) {x, last[y]};
last[y] = gl;
} char s[N];
int siz[N], son[N], val[N], dep[N], sum[N];
bool vis[N];
void dfs1(int u, int fa) {
siz[u] = 1;
for (int i = last[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (v == fa) continue;
dep[v] = dep[u] + 1;
dfs1(v, u);
siz[u] += siz[v];
if (siz[son[u]] < siz[v]) son[u] = v;
}
} void calc(int u, int fa) {
sum[dep[u]] ^= val[u];
for (int i = last[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (v == fa || vis[v]) continue;
calc(v, u);
}
return ;
} struct Node {
int h, nxt;
}a[N];
bool ans[N];
int S[N]; bool cal(int x) {
int tmp = 0;
while (x) {
tmp++;
x -= (x & (-x));
}
return tmp <= 1;
} void dfs(int u, int fa, int op) {
for (int i = last[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (v == fa || son[u] == v) continue;
dfs(v, u, 0);
}
if (son[u]) dfs(son[u], u, 1), vis[son[u]] = 1;
calc(u, fa); vis[son[u]] = 0;
for (int i = S[u]; i; i = a[i].nxt)
ans[i] = cal(sum[a[i].h]);
if (!op) calc(u, fa);
return ;
} int main() {
read(n), read(m);
for (int i = 2; i <= n; i++) {
int x; read(x);
add(x, i);
}
scanf("%s", s+1);
for (int i = 1; i <= n; i++) val[i] = 1<<(s[i]-'a');
dep[1] = 1;
dfs1(1, 0);
for (int i = 1; i <= m; i++) {
int h, v;
read(v), read(h);
a[i].nxt = S[v];
S[v] = i; a[i].h = h;
}
dfs(1, 0, 1);
for (int i = 1; i <= m; i++) puts(ans[i] ? "Yes" : "No");
return 0;
}

神奇的树上启发式合并 (dsu on tree)的更多相关文章

  1. 树上启发式合并 (dsu on tree)

    这个故事告诉我们,在做一个辣鸡出题人的比赛之前,最好先看看他发明了什么新姿势= =居然直接出了道裸题 参考链接: http://codeforces.com/blog/entry/44351(原文) ...

  2. 【CF600E】Lomset gelral 题解(树上启发式合并)

    题目链接 题目大意:给出一颗含有$n$个结点的树,每个节点有一个颜色.求树中每个子树最多的颜色的编号和. ------------------------- 树上启发式合并(dsu on tree). ...

  3. dsu on tree 树上启发式合并 学习笔记

    近几天跟着dreagonm大佬学习了\(dsu\ on\ tree\),来总结一下: \(dsu\ on\ tree\),也就是树上启发式合并,是用来处理一类离线的树上询问问题(比如子树内的颜色种数) ...

  4. 树上启发式合并(dsu on tree)学习笔记

    有丶难,学到自闭 参考的文章: zcysky:[学习笔记]dsu on tree Arpa:[Tutorial] Sack (dsu on tree) 先康一康模板题吧:CF 600E($Lomsat ...

  5. dsu on tree (树上启发式合并) 详解

    一直都没出过算法详解,昨天心血来潮想写一篇,于是 dsu on tree 它来了 1.前置技能 1.链式前向星(vector 建图) 2.dfs 建树 3.剖分轻重链,轻重儿子 重儿子 一个结点的所有 ...

  6. 【Luogu U41492】树上数颜色——树上启发式合并(dsu on tree)

    (这题在洛谷主站居然搜不到--还是在百度上偶然看到的) 题目描述 给一棵根为1的树,每次询问子树颜色种类数 输入输出格式 输入格式: 第一行一个整数n,表示树的结点数 接下来n-1行,每行一条边 接下 ...

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

    题目描述 一棵根为\(1\) 的树,每条边上有一个字符(\(a-v\)共\(22\)种). 一条简单路径被称为\(Dokhtar-kosh\)当且仅当路径上的字符经过重新排序后可以变成一个回文串. 求 ...

  8. 树上启发式合并(dsu on tree)

    树上启发式合并属于暴力的优化,复杂度O(nlogn) 主要解决的问题特点在于: 1.对于树上的某些信息进行查询 2.一般问题的解决不包含对树的修改,所有答案可以离线解决 算法思路:这类问题的特点在于父 ...

  9. hdu6191(树上启发式合并)

    hdu6191 题意 给你一棵带点权的树,每次查询 \(u\) 和 \(x\) ,求以 \(u\) 为根结点的子树上的结点与 \(x\) 异或后最大的结果. 分析 看到子树,直接上树上启发式合并,看到 ...

随机推荐

  1. cJSON结构体构建

    cJSON结构体构建 一:cJSON的构建. int create_objects() { cJSON *root, *fmt, *img, *thm, *fld; char *out; int i; ...

  2. 认识Web前端、Web后端、桌面app和移动app新开发模式 - 基于Node.js环境和VS Code工具

    认识Web.桌面和移动app新开发模式 - 基于Node.js环境和VS Code工具 一.开发环境的搭建(基于win10) 1.安装node.js和npm 到node.js官网下载安装包(包含npm ...

  3. [GO]通过结构体生成json

    package main import ( "encoding/json" "fmt" ) type IT struct { //一定要注意这里的成员变量的名字 ...

  4. git reset --soft --hard 区别

    [转]git reset 之 soft mixed hard选项的区别 (2014-09-09 16:54:06) 转载▼ 标签: git 分类: Linux 译注:为了避免丢失本地的修改以及orig ...

  5. 使用word写博客

    目前大部分的博客作者在写博客这件事情上都会遇到以下3个痛点:1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.2.发布到博客或公众号平台 ...

  6. APUE(5)---标准I/O库 (1)

    一.引言 标准I/O库不仅是UNIX,许多i其他操作系统都实现了标准I/O库,所以这个库由ISO C标准说明.标准I/O库处理很多细节,如缓冲区分配,以及优化的块长度执行I/O等.这使得它便于用户使用 ...

  7. 【微服务架构】SpringCloud之Hystrix断路器(六)

    一:什么是Hystrix 在分布式环境中,许多服务依赖项中的一些将不可避免地失败.Hystrix是一个库,通过添加延迟容差和容错逻辑来帮助您控制这些分布式服务之间的交互.Hystrix通过隔离服务之间 ...

  8. UT源码162

    (3)设计佣金问题的程序 commission方法是用来计算销售佣金的需求,手机配件的销售商,手机配件有耳机(headphone).手机壳(Mobile phone shell).手机贴膜(Cellp ...

  9. 优化体验之使用visual EDM之映射存储过程,datatype to Enum

    stored produce,datatype to Enum,Colored Entity,Multiple Diagrams 一:EDM给我们提供的强大功能 1. 存储过程的映射 直接灌sql到d ...

  10. 《html5 从入门到精通》读书笔记(二)

    接着上面继续记录笔记,这次要记的知识点比较多...记录下我认为比较重要的东西. 一.表单属性 1.autocomplete属性 该属性规定form或input域应该拥有自动完成功能. <form ...