dsu on tree

好吧,这个毒瘤......

树剖和启发式合并的杂合体。

用于解决静态子树问题,复杂度O(nlogn * insert时间)

因为dsu是并查集的意思所以算法名字大概就是什么树上并查集之类的鬼东西。

因为dsu是并查集的意思所以函数名字看起来会很奇怪......

主要思想是这样的:

首先仿照树剖搞出轻重子节点。

dsu到一个点的时候,dsu所有的轻子树并消除影响。

dsu重子树并保留影响,从重子节点那里继承答案。

计算自己的贡献。

插入所有轻子树并更新自己的答案。

如果自己是轻子树的话,消除自己的影响。

回溯。

可知每个点最多经过logn个重链就能到达根,所以每个点最多插入logn次。


例题:

给你一棵树以1号节点为根的树,每个节点上有一个体积为v,价值为w的物品。现
在要你统计,对于所有点i,如果只能取子树i中的物品,则容积为m的背包

至多能装总价值多少的物品。 n <= 50000 m <= 300

跟大部分dsu on tree有点区别,因为是树形背包变种所以不用消除轻子树影响。

首先考虑正常背包:

计算完子节点后merge子节点和自己,复杂度V²

总共nV²会超时。

然后考虑dsu on tree:

把重儿子memcpy给自己,然后依次insert每个轻儿子,虽然看起来比之前那个慢但是实际上...

复杂度mnlogn,显得十分之快...

 #include <cstdio>
#include <algorithm>
#include <cstring>
const int N = , M = ;
struct Edge {
int v, nex;
}edge[N]; int t;
int e[N], son[N], siz[N];
int f[N][M], cost[N], val[N], V; inline void add(int x, int y) {
t++;
edge[t].v = y;
edge[t].nex = e[x];
e[x] = t;
return;
} void DFS_1(int x) {
siz[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
DFS_1(y);
siz[x] += siz[y];
if(siz[y] > siz[son[x]]) {
son[x] = y;
}
}
return;
} void insert(int x, int p) {
for(int i = V; i >= cost[x]; i--) {
f[p][i] = std::max(f[p][i], f[p][i - cost[x]] + val[x]);
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
insert(y, p);
}
return;
} void dsu(int x) {
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == son[x]) {
continue;
}
dsu(y);
}
if(son[x]) {
dsu(son[x]);
memcpy(f[x], f[son[x]], sizeof(f[x]));
}
for(int i = V; i >= cost[x]; i--) {
f[x][i] = std::max(f[x][i], f[x][i - cost[x]] + val[x]);
}
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == son[x]) {
continue;
}
insert(y, x);
}
return;
} int main() {
int n;
scanf("%d%d", &n, &V);
for(int i = ; i <= n; i++) {
scanf("%d%d", &cost[i], &val[i]);
}
for(int i = , x; i <= n; i++) {
scanf("%d", &x);
add(x, i);
}
DFS_1();
dsu();
for(int i = ; i <= n; i++) {
printf("%d ", f[i][V]);
}
return ;
}

AC代码


CF 600E Lomsat gelral

题意:求树上每个子树中出现次数最多的颜色。如果有相同次数就颜色相加。

套路:先走轻儿子,传清空标记。

然后走重儿子,不清空。继承答案。

统计自己的贡献。

insert轻儿子并统计答案。

如果有清空标记就清空。

 #include <cstdio>
const int N = ;
typedef long long LL;
struct Edge {
int v, nex;
}edge[N << ]; int top;
int e[N], val[N], bin[N], large[N], son[N], siz[N];
LL ans[N]; inline void add(int x, int y) {
top++;
edge[top].v = y;
edge[top].nex = e[x];
e[x] = top;
return;
} void DFS_1(int x, int f) {
siz[x] = ;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) {
continue;
}
DFS_1(y, x);
siz[x] += siz[y];
if(siz[y] > siz[son[x]]) {
son[x] = y;
}
}
return;
} void insert(int x, int f, int p) {
bin[val[x]]++;
if(bin[val[x]] > large[p]) {
large[p] = bin[val[x]];
ans[p] = val[x];
}
else if(bin[val[x]] == large[p]) {
ans[p] += val[x];
} for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y != f) {
insert(y, x, p);
}
}
return;
} void erase(int x, int f) {
bin[val[x]]--;
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y != f) {
erase(y, x);
}
}
return;
} void dsu(int x, int f, int k) {
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f || y == son[x]) {
continue;
}
dsu(y, x, );
}
if(son[x]) {
dsu(son[x], x, );
ans[x] = ans[son[x]];
large[x] = large[son[x]];
} bin[val[x]]++;
if(bin[val[x]] > large[x]) {
large[x] = bin[val[x]];
ans[x] = val[x];
}
else if(bin[val[x]] == large[x]) {
ans[x] += val[x];
} for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f || y == son[x]) {
continue;
}
insert(y, x, x);
}
if(!k) {
erase(x, f);
}
return;
} int main() {
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &val[i]);
}
for(int i = , x, y; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
DFS_1(, );
dsu(, , );
for(int i = ; i <= n; i++) {
printf("%I64d ", ans[i]);
}
return ;
}

AC代码

一开始WA了第25个点,没找出错来,仔细思考发现答案可能是n²级别的,爆int了,开long long之后A掉。

OSU! on tree的更多相关文章

  1. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  2. SAP CRM 树视图(TREE VIEW)

    树视图可以用于表示数据的层次. 例如:SAP CRM中的组织结构数据可以表示为树视图. 在SAP CRM Web UI的术语当中,没有像表视图(table view)或者表单视图(form view) ...

  3. 无限分级和tree结构数据增删改【提供Demo下载】

    无限分级 很多时候我们不确定等级关系的层级,这个时候就需要用到无限分级了. 说到无限分级,又要扯到递归调用了.(据说频繁递归是很耗性能的),在此我们需要先设计好表机构,用来存储无限分级的数据.当然,以 ...

  4. 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...

  5. Leetcode 笔记 110 - Balanced Binary Tree

    题目链接:Balanced Binary Tree | LeetCode OJ Given a binary tree, determine if it is height-balanced. For ...

  6. Leetcode 笔记 100 - Same Tree

    题目链接:Same Tree | LeetCode OJ Given two binary trees, write a function to check if they are equal or ...

  7. Leetcode 笔记 99 - Recover Binary Search Tree

    题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...

  8. Leetcode 笔记 98 - Validate Binary Search Tree

    题目链接:Validate Binary Search Tree | LeetCode OJ Given a binary tree, determine if it is a valid binar ...

  9. Leetcode 笔记 101 - Symmetric Tree

    题目链接:Symmetric Tree | LeetCode OJ Given a binary tree, check whether it is a mirror of itself (ie, s ...

随机推荐

  1. Git代码管理

    持续更新中...   有道笔记链接:http://note.youdao.com/noteshare?id=10a0a86a3499f92cf26371f2698b97d2   Git网上平台 Git ...

  2. Elasticsearch 安装操作手册

    第一部分 ES安装环境的准备和初始化 现在交心的版本Elasticsearch 5.6.3 官方建议安装Oracle的JDK8,安装前先检查机器是否已安装JDK. Step 1 检查环境机器是否已安装 ...

  3. SQL Server实际执行计划COST"欺骗"案例

    有个系统,昨天Support人员发布了相关升级脚本后,今天发现系统中有个功能不能正常使用了,直接报超时了(Timeout expired)的错误.定位到相关相关存储过程后,然后在优化分析的过程中,又遇 ...

  4. js 学习之路6: if...else...条件语句的使用

    1.1 if (...) { ... } else { ... } <!DOCTYPE html> <html> <meta http-equiv="Conte ...

  5. Zabbix监控USG6300防火墙及交换机

    1.登录防火墙直接在web上面配置SNMP,只读团体名.读写团体名.Trap接收主机.安全名,点击应用完成防火墙上面的SNMP配置,如果你的命令行敲得6,可以使用命令行敲,配置效果一样,交换机没有这么 ...

  6. #022 Python 实验课

    拍7游戏 描述 “拍7游戏”规则是:一堆人围成一圈,开始时,任意指定一人说出数字“1”后,一圈人按顺时针方向,每人按整数由小到大的顺序一人一个地报出后续数字“2”.“3”......,当遇到为“7”的 ...

  7. kernel笔记——VFS

    vfs(the virtual filesystem, virtual file switch)为应用程序访问文件提供了统一的接口,如read.write.open等. 下面我们看加载文件系统模块.格 ...

  8. day22-多并发编程基础(三)

    今天学习了并发编程中的最后一部分,协程,也是python中区别于java,c等语言中很大不同的一部分 1.协程产生的背景 2.协程的概念 3.yield模拟协程 4.协程中主要的俩个模块 5.协程的应 ...

  9. mongodb安装4.0(rpm)

    虚拟机客户端vmware player linux版本:CentOS Linux release 7.4.1708 (Core) CentOS安装类型:Basic Web Server 参照官网最新文 ...

  10. Java多线程之ReentrantLock与Condition

    一.ReentrantLock 1.ReentrantLock简介 ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”.ReentrantLock 类实现了 Lock ,它拥有与 sy ...