3189. Lomsat gelral

题目链接

3189. Lomsat gelral

给定一棵由 n 个节点组成的树。

树的节点编号为 1n,其中 1 号节点为树的根节点。

每个节点上都标有某种颜色。

i 个节点上的颜色为 ci

如果在以节点 v 为根节点的子树中,没有任何颜色的出现次数超过颜色 c 的出现次数,那么我们称颜色 c 为该子树的主要颜色。

一些子树的主要颜色可能不止一种。

以节点 v 为根节点的子树由节点 v 以及到达根节点的路径中包含节点 v 的其它所有节点共同组成。

对于每个节点 v(1vn),请你求出以该节点为根节点的子树的所有主要颜色之和。

输入格式

第一行包含整数 n

第二行包含 n 个整数 ci,表示每个节点的颜色编号。

接下来 n1 行,每行包含两个整数 x,y 表示节点 xy 之间存在一条边。

注意,节点 1 为树的根节点。

输出格式

共一行,输出 n 个整数,其中第 i 个整数表示以节点 i 为根节点的子树的所有主要颜色之和。

数据范围

1n105,
1cin,
1x,yn

输入样例1:

4 1 2 3 4 1 2 2 3 2 4

输出样例1:

10 9 3 4

输入样例2:

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

输出样例2:

6 5 4 3 2 3 3 1 1 3 2 2 1 2 3

解题思路

启发式合并,树上启发式合并

由下而上计算答案,对于一个根节点来说每次计算一棵子树都需要清零防止对相邻子树产生影响,而计算最后一棵子树时不用清零,直接回溯到根节点再统计根节点的贡献即可,直觉上应该选择重儿子所在的子树。具体说,先处理轻儿子所在的子树,同时每处理一棵轻儿子所在的子树后清零计数器,最后处理重儿子后不清零,再计数那些轻儿子计算当前根节点贡献,关键在于 dfs 的写法

复杂度证明:对于每个节点,其被计算的规模取决于上面轻边的数量,而如果遇上一条轻边,其子树大小至少变为原来的 2 倍,故最多有 O(logn) 条轻边,故:

  • 时间复杂度:O(nlogn)

代码

// Problem: Lomsat gelral // Contest: AcWing // URL: https://www.acwing.com/problem/content/3191/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=1e5+5; int n,color[N],son[N],sz[N],cnt[N]; LL res[N],sum; int mx; vector<int> adj[N]; int dfs_son(int x,int fa) { sz[x]=1; for(int y:adj[x]) { if(y==fa)continue; sz[x]+=dfs_son(y,x); if(sz[son[x]]<sz[y])son[x]=y; } return sz[x]; } void update(int x,int fa,int sign,int s) { int c=color[x]; cnt[c]+=sign; if(mx<cnt[c])mx=cnt[c],sum=c; else if(cnt[c]==mx)sum+=c; for(int y:adj[x]) { if(y==fa||y==s)continue; update(y,x,sign,0); } } void dfs(int x,int fa,int op) { for(int y:adj[x]) { if(y==fa||y==son[x])continue; dfs(y,x,0); } if(son[x])dfs(son[x],x,1); update(x,fa,1,son[x]); res[x]=sum; if(!op)update(x,fa,-1,0),sum=mx=0; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&color[i]); for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); adj[x].pb(y),adj[y].pb(x); } dfs_son(1,0); dfs(1,0,1); for(int i=1;i<=n;i++)printf("%lld ",res[i]); return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16485275.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示