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. QT信号槽connect的第五个参数

    用过QT的小伙伴都知道连接信号槽的connect方法,但是这个方法有第五个参数,一般都是用的默认的 connect(th,SIGNAL(started()),tmpmyobject,SLOT(show ...

  2. gitbook 入门教程之导出电子书

    gitbook 既可以将源码文件单独输出,也可以仅输出单个文件,常见的导出电子书格式主要有三种(ePub, Mobi, PDF),而这三种格式都依赖于系统本身提供的 ebook-convert 工具. ...

  3. Git使用入门笔记

    1. 创建并初始化一个 代码仓库 (repository) $ git init 2.查看当前状态 $ git status 3. 将修改后的文件推入缓冲区 $ git add <filenam ...

  4. MS SQL自定义函数判断是否正整数

    可以写一个函数: 主要是使用正则来判断.另外输入字符是空的话,使用"-"来替换. CREATE FUNCTION [dbo].[svf_NonNegativeInteger] ( ...

  5. Sqlite3-安装使用

    Sqlite安装 请访问 SQLite 下载页面,从 Windows 区下载预编译的二进制文件. 您需要下载 sqlite-tools-win32-*.zip 和 sqlite-dll-win32-* ...

  6. js学习之路2: JavaScript 变量

    1. 变量的创建 首先,可以创建一个变量 var firstVar; 这时候,并没有给它赋值.这个变量还是空的. 然后,我们可以给这个变量赋值. firstVar = 128: 2. 变量的赋值 变量 ...

  7. Python开发【内置模块篇】日志模块

    logging配置 import logging logging.basicConfig(level=logging.WARNING, format='%(asctime)s %(filename)s ...

  8. koa 中间件

    什么是 Koa 的中间件 通俗的讲:中间件就是匹配路由之前或者匹配路由完成做的一系列的操作,我们就可以 把它叫做中间件. 在express中间件(Middleware)是一个函数,它可以访问请求对象( ...

  9. js 获取输入框中光标的索引位置

    <html> <head></head> <body> <script> function getTxt1CursorPosition(){ ...

  10. WiFi其他方法和WiFi事件响

    https://blog.csdn.net/Naisu_kun/article/details/86079455 目的WiFi在使用过程中并非会一直如希望般稳定运行的,为了应对这些情况就需要能够了解W ...