第一次AC这道题,是三年前的一个下午,也许晚上也说不定。当时使用的\(DSU\) \(on\) \(tree\)算法,如今已经淡忘,再学习新的算法过程中,却与旧物重逢。生活中充满不可知会的相遇,即使重逢时多是物是人非。我又想起十六岁时在上海那个船上的夜晚,两岸的霓虹在无边黑暗中照亮了她的脸庞,绿衣在少年的眼瞳里凝滞了时间,那真是个美丽的夜晚,即使看不见星月。前天她给我说说点了个赞,我都高兴了好久,真是卑微呵。那么人世中所有明知卑微却不求告解的人,就是可悲吗?大抵是有更深沉的缘由的,比如最初的悸动从不属于初恋的对象,而是属于动情者的青葱。诗人和舔狗多少是有些区别的,虽然不多,而对于沿叶节点向根的路途,上面的答案会有下面的影响,所以至下而上一路合并即可。合并的过程中,若是同时抵达叶节点,两颗原本子树代表的颜色应该别无二致。树是权值的,一种颜色对应一个节点,所以\(dfs\)过程中针对颜色单点对应节点修改。至于关键的\(push\) \(up\),多者则独上,相同则齐加,生活亦然。

# include "bits/stdc++.h"
using namespace std;
constexpr int N = 1e5 + 3;
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n;
cin >> n;
vector<int> col(n + 1);
for(int i = 1; i <= n; ++i) cin >> col[i];
vector G(n + 1, vector<int>());
for(int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
struct node {
int l, r, tot;
long long sum;
};
# define ls t[rt].l
# define rs t[rt].r
# define lson t[rt].l, l, mid
# define rson t[rt].r, mid + 1, r
vector<node> t(N * 50);
auto push_up = [&](int rt) -> void {
if(t[ls].tot == t[rs].tot) {
t[rt].tot = t[ls].tot;
t[rt].sum = t[ls].sum + t[rs].sum;
}
else if(t[ls].tot > t[rs].tot) {
t[rt].tot = t[ls].tot;
t[rt].sum = t[ls].sum;
}
else {
t[rt].tot = t[rs].tot;
t[rt].sum = t[rs].sum;
}
};
vector<int> rt(n + 1, 0);
int tree_index = n; // 1~n node has their names
auto update = [&](auto update, int &rt, int l, int r, int x) -> void {
if(!rt) rt = ++tree_index;
if(l == r) {
++t[rt].tot;
t[rt].sum = l;
return;
}
int mid = l + r >> 1;
if(x <= mid)
update(update, lson, x);
else
update(update, rson, x);
push_up(rt);
};
auto merge = [&](auto merge, int x, int y, int l, int r) -> int {
if(!x || !y) return x | y;
if(l == r) {
t[x].tot += t[y].tot;
t[x].sum = l;
return x;
}
int mid = l + r >> 1;
t[x].l = merge(merge, t[x].l, t[y].l, l, mid);
t[x].r = merge(merge, t[x].r, t[y].r, mid + 1, r);
push_up(x);
return x;
};
vector<long long> ans(n + 1);
auto dfs = [&](auto dfs, int u, int father) -> void {
for(auto v : G[u]) {
if(v == father) continue;
dfs(dfs, v, u);
merge(merge, u, v, 1, n);
}
update(update, u, 1, n, col[u]);
ans[u] = t[u].sum;
};
dfs(dfs, 1, 0);
for(int i = 1; i <= n; ++i) cout << ans[i] << " ";
return 0;
}

codeforces600E Lomsat gelral【线段树合并/DSU】的更多相关文章

  1. CF600E Lomsat gelral——线段树合并/dsu on tree

    题目描述 一棵树有$n$个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. 这个题意是真的窒息...具体意思是说,每个节点有一个颜色,你要找的是每个子树中颜色的众数 ...

  2. CodeForces600E Lomsat gelral 线段树合并

    从树上启发式合并搜出来的题 然而看着好像线段树合并就能解决??? 那么就用线段树合并解决吧 维护\(max, sum\)表示值域区间中的一个数出现次数的最大值以及所有众数的和即可 复杂度\(O(n \ ...

  3. codeforces 600E . Lomsat gelral (线段树合并)

    You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour. Let's cal ...

  4. CF600E:Lomsat gelral(线段树合并)

    Description 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. Input 第一行一个$n$.第二行$n$个数字是$c[i]$.后面$n-1$ ...

  5. bzoj3307雨天的尾巴(权值线段树合并/DSU on tree)

    题目大意: 一颗树,想要在树链上添加同一物品,问最后每个点上哪个物品最多. 解题思路: 1.线段树合并 假如说物品数量少到可以暴力添加,且树点极少,我们怎么做. 首先在一个树节点上标记出哪些物品有多少 ...

  6. codeforces 600E E. Lomsat gelral (线段树合并)

    codeforces 600E E. Lomsat gelral 传送门:https://codeforces.com/contest/600/problem/E 题意: 给你一颗n个节点的树,树上的 ...

  7. CF600E Lomsat gelral 【线段树合并】

    题目链接 CF600E 题解 容易想到就是线段树合并,维护每个权值区间出现的最大值以及最大值位置之和即可 对于每个节点合并一下两个子节点的信息 要注意叶子节点信息的合并和非叶节点信息的合并是不一样的 ...

  8. CF600E Lomsat gelral (线段树合并)

    相当于是线段树合并的模板题,比(雨天的尾巴)还要板. 唯一注意的是线段树的更新,因为同一子树中可能有多种颜色占主导地位,要输出编号和,比如一颗子树中,1出现3次(最多),3出现3次,那么应该输出4. ...

  9. [Codeforces600E] Lomsat gelral(树上启发式合并)

    [Codeforces600E] Lomsat gelral(树上启发式合并) 题面 给出一棵N个点的树,求其所有子树内出现次数最多的颜色编号和.如果多种颜色出现次数相同,那么编号都要算进答案 N≤1 ...

随机推荐

  1. GoF的23种设计模式的功能

    GoF的23种设计模式的功能 前面说明了 GoF 的 23 种设计模式的分类,现在对各个模式的功能进行介绍. 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取 ...

  2. torch.nn.MSELoss()函数解读

    转载自:https://www.cnblogs.com/tingtin/p/13902325.html

  3. 快速 IO

    IO 的进化史 cin和cout 刚开始学的时候,老师叫我们用 cin 和 cout 大概是因为这最简单吧 cin>>x; cout<<x scanf和printf 学到函数了 ...

  4. 竟然还有人说ArrayList是2倍扩容,今天带你手撕ArrayList源码

    ArrayList是我们开发中最常用到的集合,但是很多人对它的源码并不了解,导致面试时,面试官问的稍微深入的问题,就无法作答,今天我们一起来探究一下ArrayList源码. 1. 简介 ArrayLi ...

  5. C语言- 基础数据结构和算法 - 栈的链式存储

    听黑马程序员教程<基础数据结构和算法 (C版本)>, 照着老师所讲抄的, 视频地址https://www.bilibili.com/video/BV1vE411f7Jh?p=1 喜欢的朋友 ...

  6. 使用Group By子句的时候,一定要记住下面的一些规则

    使用Group By子句的时候,一定要记住下面的一些规则:(1)不能Group By非标量基元类型的列,如不能Group By text,image或bit类型的列(2)Select指定的每一列都应该 ...

  7. 设置C#启动进程但不显示命令行窗口

    设置一下Process类型相关的配置属性即可,直接上代码. //记得引入命名空间 //using System.Diagnostics; //获得当前环境的基路径 string basePath = ...

  8. UiPath键盘操作的介绍和使用

    一.键盘操作的介绍 模拟用户使用键盘操作的一种行为: 例如使用发送热键(Sendhotkey),输入信息 (Typeinto)的操作 二.键盘操作在UiPath中的使用 1.打开设计器,在设计库中新建 ...

  9. Python教程:随机验证码生成和join 字符串

    函数:string.join() Python中有join()和os.path.join()两个函数,具体作用如下: join(): 连接字符串数组.将字符串.元组.列表中的元素以指定的字符(分隔符) ...

  10. ASP.NET Core 6 从入门到企业级实战开发应用技术汇总

    系列目录     [已更新最新开发文章,点击查看详细] 本系列博客主要介绍.NET6相关技术,从基础入门.进阶提升到高级升华,最后通过一个企业级项目实战来检验技术应用能力.把个人技术与经验分享出来,抛 ...