博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
dsu on tree(CF600E Lomsat gelral)
阅读量:6943 次
发布时间:2019-06-27

本文共 2283 字,大约阅读时间需要 7 分钟。

题意

一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。

dsu on tree

用来解决子树问题

好像不能带修改??

暴力做这个题,就是每次扫一遍子树统计答案

时间\(O(n^2)\)

或者会高级的数据结构解决

空间,编程难度是个挑战

然而\(dsu \ on \ tree\)树上启发式合并则是一个好方法

它通过增加对重儿子子树信息的利用来提高效率

流程:

递归轻儿子

递归重儿子
统计答案
如果该点为它父亲的重儿子,保存信息
否则删除信息

复杂度分析:

每个点被扫到的次数只有它到根的路径上轻边的次数*\(2\)
也就是\(log\)
那么总复杂度为空间\(O(n)\),时间\(O(nlogn)\)

该题代码

# include 
# define IL inline# define RG register# define Fill(a, b) memset(a, b, sizeof(a))using namespace std;typedef long long ll;IL int Input(){ RG int x = 0, z = 1; RG char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z;}const int maxn(1e5 + 5);int n, first[maxn], cnt, col[maxn], size[maxn], son[maxn], vis[maxn], num[maxn], mx;ll sum[maxn], ans[maxn];struct Edge{ int to, next;} edge[maxn << 1];IL void Add(RG int u, RG int v){ edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;}IL void Dfs(RG int u, RG int ff){ size[u] = 1; for(RG int e = first[u]; e != -1; e = edge[e].next){ RG int v = edge[e].to; if(v != ff){ Dfs(v, u); size[u] += size[v]; if(size[v] > size[son[u]]) son[u] = v; } }}IL void Update(RG int u, RG int ff, RG int val){ sum[num[col[u]]] -= col[u]; num[col[u]] += val; sum[num[col[u]]] += col[u]; if(val > 0) mx = max(mx, num[col[u]]); else while(mx && !sum[mx]) --mx; for(RG int e = first[u]; e != -1; e = edge[e].next) if(edge[e].to != ff && !vis[edge[e].to]) Update(edge[e].to, u, val);}IL void Solve(RG int u, RG int ff, RG int op){ size[u] = 1; for(RG int e = first[u]; e != -1; e = edge[e].next) if(edge[e].to != ff && edge[e].to != son[u]) Solve(edge[e].to, u, 0); if(son[u]) Solve(son[u], u, 1), vis[son[u]] = 1; Update(u, ff, 1), vis[son[u]] = 0; ans[u] = sum[mx]; if(!op) Update(u, ff, -1);}int main(){ n = Input(); for(RG int i = 1; i <= n; ++i) col[i] = Input(), first[i] = -1; for(RG int i = 1; i < n; ++i){ RG int u = Input(), v = Input(); Add(u, v), Add(v, u); } Dfs(1, 0), Solve(1, 0, 1); for(RG int i = 1; i <= n; ++i) printf("%lld ", ans[i]); return 0;}

转载于:https://www.cnblogs.com/cjoieryl/p/9116072.html

你可能感兴趣的文章
windows调试器之Visual C++
查看>>
如何删除存在多个重复记录中的一个
查看>>
Android开发之旅:环境搭建及HelloWorld
查看>>
请求浏览器使用chrome查看http请求
查看>>
数据数据包JAVASE----17----网络编程
查看>>
OC基础知识
查看>>
matlab之并行
查看>>
泛型类型通常在Dao和Service 中使用BaseDao<T extends Serializable>的泛型
查看>>
关于java的JIT知识
查看>>
设备编程[置顶] Linux 设备编程
查看>>
冒泡、选择、插入排序
查看>>
SQL简单的日报和月报
查看>>
listView 分页加载数据
查看>>
【体系结构】转移预测器性能的定量评价
查看>>
[置顶] 浅谈软件质量管理
查看>>
Storm-源码分析-Topology Submit-Task
查看>>
POJ 2632 Crashing Robots (坑爹的模拟题)
查看>>
[转载]ubuntu发热问题解决
查看>>
__stdcall,__cdecl,_cdecl,_stdcall,。__fastcall,_fastcall 区别简介
查看>>
Chapter 1 -- UsingAndAvoidingNull
查看>>