题目描述

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

  这个题意是真的窒息。。。具体意思是说,每个节点有一个颜色,你要找的是每个子树中颜色的众数(可能有多个),比如子树中有$3个2,3个1,3个5,那么2,1,5都是众数,答案为2+1+5=8$。

思路

做法一:

  线段树合并。权值线段树覆盖颜色$1->100000,用sum$表示颜色最多出现的次数,$ans$表示答案。分$3种情况pushup$即可。

  1. 左右子树$sum$相等
  2. 左边$>$右边
  3. 左边$<$右边

  $dfs的时候merge$一下即可。

code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#define smid (l+r>>1)
#define I inline
using namespace std;
typedef long long LL;
const int N=;
LL col[N];
LL maxcol;
int n;
int ls[N*],rs[N*],cnt,rt[N];
LL sum[N*],ans[N*];
vector<int>g[N];
LL out[N]; I void pushup(int now)
{
if(sum[ls[now]]==sum[rs[now]])
{
sum[now]=sum[ls[now]];
ans[now]=ans[ls[now]]+ans[rs[now]];
}
else if(sum[ls[now]]<sum[rs[now]])
{
sum[now]=sum[rs[now]];
ans[now]=ans[rs[now]];
}
else
{
sum[now]=sum[ls[now]];
ans[now]=ans[ls[now]];
}
} I void modify(int &now,int l,int r,int pos)
{
if(!now)now=++cnt;
if(l==r)
{
sum[now]++;ans[now]=l;
return;
}
if(pos<=smid)modify(ls[now],l,smid,pos);
else modify(rs[now],smid+,r,pos);
pushup(now);
} I int merge(int x,int y,int l,int r)
{
if(!x||!y)return x+y;
if(l==r)
{
sum[x]+=sum[y];ans[x]=l;
return x;
}
ls[x]=merge(ls[x],ls[y],l,smid);
rs[x]=merge(rs[x],rs[y],smid+,r);
pushup(x);
return x;
} I void dfs(int u,int fa)
{
for(int i=;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa)continue;
dfs(v,u);
merge(rt[u],rt[v],,);
}
modify(rt[u],,,col[u]);
out[u]=ans[rt[u]];
} int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=;i<=n;i++)
{
cin>>col[i];
rt[i]=i;cnt++;
}
for(int i=;i<n;i++)
{
int x,y;cin>>x>>y;
g[x].push_back(y);g[y].push_back(x);
}
dfs(,);
for(int i=;i<=n;i++)
{
cout<<out[i]<<" ";
}
}

洛谷上交不了,必须到$CF$上交,但是$CF$上不给用scanf("%lld"),就加了$cin$加速。

做法二:

  树上启发式合并。这里当做板子题来讲。$dsu on tree$是个啥?其实就是优化的暴力,对于一棵树,我们定义节点$u的重儿子son[u]为其size$最大的儿子,其余为轻儿子。这个算法主要用于:

  1. 只有对子树的询问
  2. 没有修改操作

  回到这个题目:首先我们考虑暴力$dfs$:遍历每个节点的子树,统计颜色出现的个数,得出当前的的答案,再清空当前点的影响,继续$dfs$,这个算法是$O(n^2)$的,于是我们使用一些重链剖分的性质,搞一个树上启发式合并。具体流程如下:

  1. $dfs$遍历每个节点
  2. 先递归所有轻儿子,跑到底层,不保留这一次$dfs$的答案
  3. 递归重儿子,保留这一次$dfs$的答案
  4. 重儿子所在子树被处理完了,而且又保留了答案,只剩下当前节点的轻儿子了
  5. 暴力统计所有轻儿子所在子树的答案
  6. 通过上面两步得出当前点的答案
  7. 如果是轻儿子就清空当前点对答案的影响

主体框架

code(比较板子)

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cstdio>
#define I inline
using namespace std;
const int N=;
typedef long long LL;
int sz[N],son[N],n,col[N],Son;
vector<int>g[N];
LL cnt[N],mx,ans[N],sum; I int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
} I void gets(int u,int fa)
{
sz[u]=;
for(int i=;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa)continue;
gets(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
} I void add(int u,int fa,int val)
{
cnt[col[u]]+=val;
if(mx==cnt[col[u]])sum+=LL(col[u]);
if(mx<cnt[col[u]])sum=col[u],mx=cnt[col[u]];
for(int i=;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa||v==Son)continue;
add(v,u,val);
}
} I void dfs(int u,int fa,bool opt)//opt为是否保留答案
{
for(int i=;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa||v==son[u])continue;
dfs(v,u,);//递归处理所有轻儿子
}
if(son[u])dfs(son[u],u,),Son=son[u];
//处理所有重儿子并得到重儿子所在子树答案
add(u,fa,);//得到轻儿子所在子树的答案
Son=;//注意这里,如果要消除影响,重儿子的影响也要消除
ans[u]=sum;//得出答案
if(!opt)add(u,fa,-),sum=,mx=;//消除影响,看情况要不要加add函数
} int main()
{
n=read();
for(int i=;i<=n;i++)col[i]=read();
for(int i=;i<n;i++)
{
int x=read(),y=read();
g[x].push_back(y);g[y].push_back(x);
}
gets(,);
dfs(,,);
for(int i=;i<=n;i++)printf("%lld ",ans[i]);
}

CF600E Lomsat gelral——线段树合并/dsu on tree的更多相关文章

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

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

  2. 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 ...

  3. CodeForces600E Lomsat gelral 线段树合并

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

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

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

  5. 【UOJ#388】【UNR#3】配对树(线段树,dsu on tree)

    [UOJ#388][UNR#3]配对树(线段树,dsu on tree) 题面 UOJ 题解 考虑一个固定区间怎么计算答案,把这些点搞下来建树,然后\(dp\),不难发现一个点如果子树内能够匹配的话就 ...

  6. codeforces600E Lomsat gelral【线段树合并/DSU】

    第一次AC这道题,是三年前的一个下午,也许晚上也说不定.当时使用的\(DSU\) \(on\) \(tree\)算法,如今已经淡忘,再学习新的算法过程中,却与旧物重逢.生活中充满不可知会的相遇,即使重 ...

  7. CF600E Lomsat gelral 树上启发式合并

    题目描述 有一棵 \(n\) 个结点的以 \(1\) 号结点为根的有根树. 每个结点都有一个颜色,颜色是以编号表示的, \(i\) 号结点的颜色编号为 \(c_i\)​. 如果一种颜色在以 \(x\) ...

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

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

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

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

随机推荐

  1. dubbo配置负载均衡、集群环境

    再用dubbo作为项目架构的时候,给consumer消费者用nginx提供了负载均衡策略和集群的实现, 但是想了下,consumer再多,但是提供者还是一个,最后还不都是落到了这一个provider上 ...

  2. 【从刷面试题到构建知识体系】Java底层-synchronized锁-1

    在技术论坛中,经常看到一种言论:面试造火箭,干活拧螺丝.我们平时写的大部分代码的确是CRDU,再提一个层次,也无非就是揉进去复杂一些的业务逻辑,把一堆的CRDU组合起来. 那么问题来了:我们提倡的研究 ...

  3. GDB使用总结

    1. GDB概述 GNU发布的调试器,可以查看程序如何运行或崩溃时的状态. 主要功能: 启动程序,可以按照自定义的要求运行程序. 可让被调试的程序在你所指定的断点处停住. 当程序被停住时,可以检查此时 ...

  4. java集合类之LinkedList详解

    一.LinkedList简介 由于LinkedList是一个实现了Deque的双端队列,所以LinkedList既可以当做Queue,又可以当做Stack,在将LinkedList当做Stack时,使 ...

  5. Cutting Sticks UVA - 10003

    题文: 见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_proble ...

  6. Go routine 编排框架:oklog/run 包

    目录 Go routine 编排框架:oklog/run 包 问题引入 oklog/run 包介绍 使用例子 参考资料 Go routine 编排框架:oklog/run 包 问题引入 oklog/r ...

  7. 代码审计-YXcms1.4.7

    题外: 今天是上班第一天,全都在做准备工作,明天开始正式实战做事. 看着周围稍年长的同事和老大做事,自己的感觉就是自己还是差的很多很多,自己只能算个废物. 学无止境,我这样的垃圾废物就该多练,保持战斗 ...

  8. 机器学习:数据清洗及工具OpenRefine

    数据分析中,首先要进行数据清洗,才可以继续训练模型,预测等操作. 首先介绍一下什么是数据清洗(定义来自 百度百科,有删减) 数据清洗从名字上也看的出就是把“脏”的“洗掉”,指发现并纠正数据文件中可识别 ...

  9. [JZOJ5456]【NOIP2017提高A组冲刺11.6】奇怪的队列

    Description nodgd的粉丝太多了,每天都会有很多人排队要签名.今天有

  10. SpringMVC4拦截器配置遇到的坑

    目的:对get请求添加token验证(若为post请求可通过RequestBodyAdvice实现). 情景:因为有api版本管理的需求,重写了WebMvcConfigurationSupport类的 ...