题目大意:给定一棵 N 个节点的有根树,1 号节点是树的根节点,每个节点有一个颜色。求对于每个节点来说,能够支配整棵子树的颜色之和是多少。支配的定义为对于以 i 为根的子树,该颜色出现的次数不小于任何其他颜色出现的次数。

题解:学会了 dsu on tree。

树上启发式合并算法是一种对暴力的优化算法。对于暴力算法来说,直接遍历每个节点,再遍历该节点对应的子树寻找答案,时间复杂度显然为 \(O(n^2)\)。考虑进行优化,显然对于父节点来说,遍历到的最后一棵子树的贡献可以不用消去,直接加在父节点对应的子树上即可。根据这条性质,每次都选择 i 的重儿子进行直接累加答案贡献,重儿子的定义和求法与树剖中重儿子相同。可以看出对于树上每个节点,在统计答案的时候仅仅遍历了子树内的所有轻边,即:重儿子对应的子树再合并时不需要再次遍历。从全局的角度来说,对于第 i 个节点为根的子树,子树在统计答案时被遍历的次数和该节点到根节点路径上的轻边个数成正比。一共只有 \(O(logn)\) 条轻边,因此,遍历 n 个节点的时间复杂度上界为 \(O(nlogn)\)。

代码如下

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
#define cls(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
const double eps=1e-6;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll fpow(ll a,ll b,ll c){ll ret=1%c;for(;b;b>>=1,a=a*a%c)if(b&1)ret=ret*a%c;return ret;}
inline ll read(){
ll x=0,f=1;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
/*------------------------------------------------------------*/ vector<int> G[maxn];
int size[maxn],son[maxn];
int n,cor[maxn],cnt[maxn];
bool skip[maxn];
ll mx,now,ans[maxn]; void getsize(int u,int fa){
size[u]=1;
for(auto v:G[u]){
if(v==fa)continue;
getsize(v,u);
if(size[v]>size[son[u]])son[u]=v;
size[u]+=size[v];
}
}
void add(int u,int fa,int val){
cnt[cor[u]]+=val;
if(val>0){
if(cnt[cor[u]]>mx)now=cor[u],mx=cnt[cor[u]];
else if(cnt[cor[u]]==mx)now+=cor[u];
}
for(auto v:G[u]){
if(v==fa||skip[v])continue;
add(v,u,val);
}
}
void dfs(int u,int fa,bool keep){
for(auto v:G[u]){
if(v==fa||v==son[u])continue;
dfs(v,u,0);
}
if(son[u])dfs(son[u],u,1),skip[son[u]]=1;
add(u,fa,1);
ans[u]=now;
if(son[u])skip[son[u]]=0;
if(!keep)add(u,fa,-1),mx=now=0;
} void read_and_parse(){
n=read();
for(int i=1;i<=n;i++)cor[i]=read();
for(int i=1,x,y;i<n;i++){
x=read(),y=read();
G[x].pb(y),G[y].pb(x);
}
}
void solve(){
getsize(1,0);
dfs(1,0,1);
for(int i=1;i<=n;i++)printf("%lld%c",ans[i],i==n?'\n':' ');
}
int main(){
read_and_parse();
solve();
return 0;
}

【CF600E】Lomsat gelral的更多相关文章

  1. 【CF600E】Lomsat gelral(dsu on tree)

    [CF600E]Lomsat gelral(dsu on tree) 题面 洛谷 CF题面自己去找找吧. 题解 \(dsu\ on\ tree\)板子题 其实就是做子树询问的一个较快的方法. 对于子树 ...

  2. 【CF600E】 Lomsat gelral

    CF600E Lomsat gelral Solution 考虑一下子树的问题,我们可以把一棵树的dfn序搞出来,那么子树就是序列上的一段连续的区间. 然后就可以莫队飞速求解了. 但是这题还有\(\T ...

  3. 【CF600E】Lomsat gelral——树上启发式合并

    (题面来自luogu) 题意翻译 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. ci <= n <= 1e5 裸题.统计时先扫一遍得到出 ...

  4. 【CF600E】Lomset gelral 题解(树上启发式合并)

    题目链接 题目大意:给出一颗含有$n$个结点的树,每个节点有一个颜色.求树中每个子树最多的颜色的编号和. ------------------------- 树上启发式合并(dsu on tree). ...

  5. 「CF600E」Lomsat gelral

    传送门 Luogu 解题思路 线段树合并板子题(也可以 dsu on the tree) 好像没什么好讲的,就是要注意开 long long . 细节注意事项 咕咕咕 参考代码 #include &l ...

  6. 【CodeForces】600 E. Lomsat gelral (dsu on tree)

    [题目]E. Lomsat gelral [题意]给定n个点的树,1为根,每个点有一种颜色ci,一种颜色占领一棵子树当且仅当子树内没有颜色的出现次数超过它,求n个答案——每棵子树的占领颜色的编号和Σc ...

  7. 【Codeforces】600E. Lomsat gelral

    Codeforces 600E. Lomsat gelral 学习了一下dsu on tree 所以为啥是dsu而不是dfs on tree??? 这道题先把这棵树轻重链剖分了,然后先处理轻儿子,处理 ...

  8. CF600E Lomsat gelral 和 CF741D Dokhtar-kosh paths

    Lomsat gelral 一棵以\(1\)为根的树有\(n\)个结点,每个结点都有一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号(若有数量一样的,则求编号和). \(n \le 10^ ...

  9. 【主席树启发式合并】【P3302】[SDOI2013]森林

    Description 给定一个 \(n\) 个节点的森林,有 \(Q\) 次操作,每次要么将森林中某两点联通,保证操作后还是个森林,要么查询两点间权值第 \(k\) 小,保证两点联通.强制在线. L ...

随机推荐

  1. 转《在浏览器中使用tensorflow.js进行人脸识别的JavaScript API》

    作者 | Vincent Mühle 编译 | 姗姗 出品 | 人工智能头条(公众号ID:AI_Thinker) [导读]随着深度学习方法的应用,浏览器调用人脸识别技术已经得到了更广泛的应用与提升.在 ...

  2. Navicat 远程连接Docker容器中的mysql 报错:1251 - Client does not support authentication protocol 解决办法。

    出现这个问题 首先进入 1.docker exec -it mysql02 bash      //mysql02是mysql容器的别名 2.mysql -uroot -p 3.输入密码 4.进入my ...

  3. debug2

    调试常用功能介绍 日常java开发中实际写代码的时间并不会很多,花在整理思路,代码重构,调试bug会占用很大部分时间. 熟练掌握调试工具,了解调试相关技巧,是java开发中减少调试时间,提高效率不可或 ...

  4. Python基础知识2-内置数据结构(上)

     分类 数值型 用浮点型的时候注意别和"=="一起使用. 数字的处理函数 注意round()函数的特殊:四舍六入五取偶 类型判断 列表list 列表list定义 初始化 列表索引访 ...

  5. 《笔记》Python itertools的groupby分组数据处理

    今天遇到这么一个需求,需要将这样的数据进行分组处理: [(, ), (, ), (, ), (, ), (, ), (, )] 处理之后我可能需要得到这样的结果: [(, (, , (, , (, ) ...

  6. 七、.net core下配置、数据库访问等操作实现

    配置读取 .net core下读取配置还是有点麻烦的,本身没有System.Configuration.dll,所以在进行配置前需要自行引用Microsoft.Extensions.Configura ...

  7. vue实例相关2

    vue data中 对象/数组 不为空,即使定义为[]/{} new Vue({ el: '#main', data: { list: [], current: {}, aa:'' } }) cons ...

  8. layui 提交表格不验证

    form.on('submit(filter_save)', function (data) { 后面查找发现是提交按钮要放在form里面

  9. SELECT IDENT_CURRENT(tableName)和自增长列的纠结

    项目中要用到一个功能:主表主键为自增长,要求在插入主表数据前先获得主表要插入数据的主键ID值,用在插入子表时获取主键ID.在网上搜了一下,发现SELECT IDENT_CURRENT(TableNam ...

  10. linq之左连接 + group by

    var list = from item in (from s in _sysBll.GetList(s => s.ParamID == "TraSchType" & ...