题目描述

  一棵树有$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. 用CSS绘制实体三角形并说明原理

    ;;margin:0 auto;border:6px solid transparent;border-top: 6px solid red;} 1.采用的是均分原理 盒子都是一个矩形或正方形,从形状 ...

  2. 清除SQL Server Management Studio的最近服务器列表

    C:\Users\dell\AppData\Roaming\Microsoft\SQL Server Management Studio\12.0\SqlStudio.bin

  3. 杂谈:开发人员如何进行复杂业务的学习?让boss刮目相看

    一点小拙见,欢迎指正 一.概述 大型复杂的软件系统,是有许多人共同协作完成的,有些产品的业务是很复杂的,其在需求文档,及开发规范上都做得很好,不然维护的人越多,没有文档和规范去限制,岂不更加乱套. 如 ...

  4. Zabbix安装与简单配置

    目录 0. 前言 1. 安装 1.1 准备安装环境 1.1.1 下载安装包 1.1.2 修改文件配置 1.2 开始安装 2. 实验环境 2.1 简易拓扑图 2.2 基本配置 3. 配置 0. 前言 不 ...

  5. C# .Net Framework

    .NET Framework概述 .NET Framework是由微软开发,一个致力于敏捷软件开发.快速应用开发.平台无关性和网络透明化的软件开发平台. .NET Framework组成 .NET F ...

  6. js随机生成验证码以及随机颜色

    Javascript通过Math.random()随机生成验证码. 代码如下: <!DOCTYPE html><html> <head> <meta char ...

  7. 《Java并发编程实战》读书笔记-第1章 简介

    并发简史 在早期的计算机中不包含操作系统,从头至尾都只执行一个程序,并且这个程序能访问计算机所有资源.操作系统的出现使得计算机每次能运行多个程序,并且不同的程序都在单独的进程中运行:操作系统为各个独立 ...

  8. Go.js 没有中文文档 也没有中文demo 学起来很费劲 给大家整理一个算是详细的文档

    <!DOCTYPE html> <html> <head> <meta name="viewport" content="wid ...

  9. xml 文件操作

      'XML添加   Public Sub Add(ID As String, RFSerialnumber As String, Mood As Integer)     If reatch(RFS ...

  10. 玩转OneNET物联网平台之MQTT服务③ —— 远程控制LED(设备自注册)

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...