Lomsat gelral CodeForces - 600E (树上启发式合并)
You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour.
Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the subtree of vertex v more times than colour c. So it's possible that two or more colours will be dominating in the subtree of some vertex.
The subtree of vertex v is the vertex v and all other vertices that contains vertex v in each path to the root.
For each vertex v find the sum of all dominating colours in the subtree of vertex v.
Input
The first line contains integer n (1 ≤ n ≤ 105) — the number of vertices in the tree.
The second line contains n integers ci (1 ≤ ci ≤ n), ci — the colour of the i-th vertex.
Each of the next n - 1 lines contains two integers xj, yj (1 ≤ xj, yj ≤ n) — the edge of the tree. The first vertex is the root of the tree.
Output
Print n integers — the sums of dominating colours for each vertex.
Examples
Input
4
1 2 3 4
1 2
2 3
2 4
Output
10 9 3 4
Input
15
1 2 3 1 2 3 3 1 1 3 2 2 1 2 3
1 2
1 3
1 4
1 14
1 15
2 5
2 6
2 7
3 8
3 9
3 10
4 11
4 12
4 13
Output
6 5 4 3 2 3 3 1 1 3 2 2 1 2 3
题意:
给你一颗以1为根的树,每一个节点有一个颜色。
询问你对于从1到n每一个节点为根的子树中,颜色最多的是哪个颜色?如果有多个颜色数量一样多,答案应该是他们的sum和。
思路:
dsu on tree 的入门题,
我们知道如果直接暴力求对于每一个节点为根的子树话,时间复杂度是 n * n的,显然会tle,的
我们可以利用树的重儿子和轻儿子的性质来优化暴力,而理论的时间复杂度是 O(nlogn)
我们从树根开始dfs,对于每一个节点,我们先暴力处理他的轻儿子,维护出清儿子的答案,同时清空轻儿子的贡献。
而对于重儿子,我们同样暴力处理,但是不删除他的贡献,因为重儿子节点可以对它的父节点有贡献,即我们在算重儿子的父节点的答案时,就不需要去扫它的重儿子了,因为已经处理过了。
同时,树链剖分的知识我们可以知道,这样处理的话,对于每一个节点,如果他是重儿子,他只会被访问1次,如果是轻儿子,最多访问logn次。所以时间复杂度是 O(nl ogn )
推荐学习本知识点的博客:https://www.cnblogs.com/zwfymqz/p/9683124.html
细节见代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int* p);
const int maxn = 100010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int n;
std::vector<int> son[maxn];
int wson[maxn];
int SZ[maxn];
int a[maxn];
void dfs1(int x,int pre)
{
SZ[x]=1;
int maxson=-1;
for(auto y:son[x])
{
if(y!=pre)
{
dfs1(y,x);
SZ[x]+=SZ[y];
if(maxson<SZ[y])
{
maxson=SZ[y];
wson[x]=y;
}
}
}
}
ll ans[maxn];
ll sum;
int isson;
int m;
ll cnt[maxn];
void add(int x,int pre,int val)
{
cnt[a[x]]+=val;
if(cnt[a[x]]>m)
{
m=cnt[a[x]];
sum=a[x];
}else if(cnt[a[x]]==m)
{
sum+=a[x];
}
for(auto y:son[x])
{
if(y==pre||y==isson)
continue;
add(y,x,val);
}
}
void dfs2(int x,int pre,int op)
{
for(auto y:son[x])
{
if(y==pre||y==wson[x])
{
continue;
}
dfs2(y,x,0);
}
if(wson[x])
{
dfs2(wson[x],x,1);
isson=wson[x];
}
add(x,pre,1);
isson=0;
ans[x]=sum;
if(op==0)
{
add(x,pre,-1);
sum=0;
m=0;
}
}
int main()
{
//freopen("D:\\code\\text\\input.txt","r",stdin);
//freopen("D:\\code\\text\\output.txt","w",stdout);
gg(n);
repd(i,1,n)
{
gg(a[i]);
}
int u,v;
repd(i,2,n)
{
gg(u);gg(v);
son[u].pb(v);
son[v].pb(u);
}
dfs1(1,0);
dfs2(1,0,0);
repd(i,1,n)
{
printf("%lld ",ans[i] );
}
printf("\n");
return 0;
}
inline void getInt(int* p) {
char ch;
do {
ch = getchar();
} while (ch == ' ' || ch == '\n');
if (ch == '-') {
*p = -(getchar() - '0');
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 - ch + '0';
}
}
else {
*p = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9') {
*p = *p * 10 + ch - '0';
}
}
}
Lomsat gelral CodeForces - 600E (树上启发式合并)的更多相关文章
- Codeforces - 600E 树上启发式合并
题意:求每一个子树存在最多颜色的颜色代号和(可重复) 本题是离线统计操作,因此可以直接合并重儿子已达到\(O(nlogn)\)的复杂度 PS.不知道什么是启发式合并的可以这样感受一下:进行树链剖分,分 ...
- 【CF600E】Lomset gelral 题解(树上启发式合并)
题目链接 题目大意:给出一颗含有$n$个结点的树,每个节点有一个颜色.求树中每个子树最多的颜色的编号和. ------------------------- 树上启发式合并(dsu on tree). ...
- Codeforces 600E - Lomsat gelral(树上启发式合并)
600E - Lomsat gelral 题意 给出一颗以 1 为根的树,每个点有颜色,如果某个子树上某个颜色出现的次数最多,则认为它在这课子树有支配地位,一颗子树上,可能有多个有支配的地位的颜色,对 ...
- CF EDU - E. Lomsat gelral 树上启发式合并
学习:http://codeforces.com/blog/entry/44351 E. Lomsat gelral 题意: 给定一个以1为根节点的树,每个节点都有一个颜色,问每个节点的子树中,颜色最 ...
- [Codeforces600E] Lomsat gelral(树上启发式合并)
[Codeforces600E] Lomsat gelral(树上启发式合并) 题面 给出一棵N个点的树,求其所有子树内出现次数最多的颜色编号和.如果多种颜色出现次数相同,那么编号都要算进答案 N≤1 ...
- 【学习笔记/题解】树上启发式合并/CF600E Lomsat gelral
题目戳我 \(\text{Solution:}\) 树上启发式合并,是对普通暴力的一种优化. 考虑本题,最暴力的做法显然是暴力统计每一次的子树,为了避免其他子树影响,每次统计完子树都需要清空其信息. ...
- Codeforces 208E - Blood Cousins(树上启发式合并)
208E - Blood Cousins 题意 给出一棵家谱树,定义从 u 点向上走 k 步到达的节点为 u 的 k-ancestor.多次查询,给出 u k,问有多少个与 u 具有相同 k-ance ...
- 树上启发式合并(dsu on tree)学习笔记
有丶难,学到自闭 参考的文章: zcysky:[学习笔记]dsu on tree Arpa:[Tutorial] Sack (dsu on tree) 先康一康模板题吧:CF 600E($Lomsat ...
- 神奇的树上启发式合并 (dsu on tree)
参考资料 https://www.cnblogs.com/zhoushuyu/p/9069164.html https://www.cnblogs.com/candy99/p/dsuontree.ht ...
随机推荐
- java:面向对象(多态,final,抽象方法,(简单工厂模式即静态方法模式),接口)
* 生活中的多态:同一种物质,因环境不同而表现不同的形态. * 程序中多态:同一个"接口",因不同的实现而执行不同的操作. * 多态和方法的重写经常结合使用,子类重写父类的方法,将 ...
- 从gopath到go mod的一次尝试
windows下的尝试: gomod初尝试下载官方包1.11(及其以上版本将会自动支持gomod) 默认GO111MODULE=auto(auto是指如果在gopath下不启用mod)go mod h ...
- vscode 中sftp配置
简单记录一下,相对路径的设置不用“/”表明根目录等,直接写目录名字即可 { "name": "profile name", "prot ...
- Linux增加虚拟内存方法
例如增加2G虚拟内存,操作如下: [root@gamedb ~]# free -m[root@gamedb tmp]# dd if=/dev/zero of=/tmp/big_swap bs=1024 ...
- C#作业系统中的安全系统
比赛条件 编写多线程代码时,总是存在竞争条件的风险.当一个操作的输出取决于其控制之外的另一个过程的定时时,发生竞争条件. 竞争条件并不总是一个错误,但它是不确定行为的来源.当竞争条件确实导致错误时,可 ...
- 【AMAD】splinter -- 用于测试web app的python框架
简介 动机 作用 用法 热度分析 个人评分 简介 Splinter1是一个开源工具,使用Python编写,用于测试web apps.它可以用来对浏览器实现自动化操作,比如访问URLs,和按钮等交互. ...
- java去除数组中的空值
public String[] deleteArrayNull(String []string) { String []array = string; // 声明一个list List<Stri ...
- vscode配置PHP Debug
1.先在vscode中安装PHP Debug,在设置添加“php.validate.executablePath”项,选中对应版本的php.exe. "php.validate.execut ...
- c++ | size_t
1.size_t的定义 size_t是一种数据相关的无符号类型,它被设计得足够大以便能够内存中任意对象的大小. 在cstddef头文件中定义了size_t类型,这个文件是C标准库stddef.h头文件 ...
- Java小知识---Java请求一个URL。获取网站返回的数据
对url发送请求,获得返回值: public static String SendGET(String url,String param){ String result="";// ...