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. Redis压缩列表

    此篇文章是主要介绍Redis在数据存储方面的其中一种方式,压缩列表.本文会介绍1. 压缩列表(ziplist)的使用场景 2.如何达到节约内存的效果?3.压缩列表的存储格式 4. 连锁更新的问题  5 ...

  2. Docker 创建 Jira Core(Jira SoftWare) 7.12.3 中文版

    目录 目录 1.介绍 1.1.什么是 JIRA Core? 1.2.什么是 JIRA SoftWare 2.JIRA 的官网在哪里? 3.如何下载安装? 4.对 JIRA 进行配置 4.1.JIRA ...

  3. javaweb学习--jsp

    阅读电子书<Java Web从入门到精通>密码:461c,学习JavaWeb基础知识.由于本人已有html基础,所以直接略过前面部分,进入jsp学习 jsp页面添加库引用,引入项目文件 引 ...

  4. 【原】Java学习笔记023 - 字符串缓冲区_正则表达式

    package cn.temptation; import java.util.Arrays; public class Sample01 { public static void main(Stri ...

  5. c/c++ linux 进程间通信系列1,使用signal,kill

    linux 进程间通信系列1,使用signal,kill 信号基本概念:  软中断信号(signal,又简称为信号)用来通知进程发生了异步事件.进程之间可以互相通过系统调用kill发送软中断信号.内核 ...

  6. CADisplayLink以及定时器的使用

    第一种: 用CADisplayLink可以实现不停重绘. - (CADisplayLink *)link { if (!_link) { // 创建定时器,一秒钟调用rotation方法60次 _li ...

  7. python3 正则表达式点星问号(.*?)能不能匹配换行符?不能的话应该怎么写

    python3的re模块使用过程中,正则的书写遇到了一些问题,就是使用.*?能不能匹配到换行符的问题. 答案是不能. 如果在匹配过程中遇到了也没关系,加上这个语句就好: \s+

  8. CentOS7中利用Xshell6向虚拟机本地上传文件

    环境交代 Linux系统:CentOS7, Xshell版本:6 操作步骤 下面我们以一个文件上传来演示用法 第一步 建立连接,这里不多说 在Xshell中点击如下图标,或者直接按 Alt+Ctrl+ ...

  9. java 非访问修饰符 final 的用法

    final 修饰符,用来修饰类.方法和变量 final修饰的类不能被继承 举例,String类是final类,不可以被继承: final修饰的方法不能被重写 只是不能重写,也就是不能被子类修改,但是可 ...

  10. java中的String整理

    基础知识模块: 参考以下博客,写得很好,深入分析了String,需要重点掌握 http://www.tiantianbianma.com/java/java-basic/page/3/ http:// ...