CF 600 E. Lomsat gelral

E. Lomsat gelral

http://codeforces.com/contest/600/problem/E

题意:

  求每个子树内出现次数最多的颜色(如果最多的颜色出现次数相同,将颜色编号求和)。

分析:

  dsu on tree。

  这个可以解决一系列不带修改的子树查询问题。

  考虑暴力的思路:就是枚举每个子树,计算每个颜色出现的个数。统计答案。

  dsu on tree:最后一个子树枚举计算完了,它的贡献可以保留,然后用其它的子树去合并。(最后一棵子树是最大的)。现在的复杂度就是nlogn了。

代码:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<cctype>
 7 #include<set>
 8 #include<vector>
 9 #include<queue>
10 #include<map>
11 using namespace std;
12 typedef long long LL;
13
14 inline int read() {
15     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1;
16     for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;return x*f;
17 }
18
19 const int N = 100005;
20
21 int head[N], nxt[N << 1], to[N << 1], En;
22 int fa[N], siz[N], son[N], cnt[N], col[N], Mx;
23 LL ans[N], Sum;
24
25 void add_edge(int u,int v) {
26     ++En; to[En] = v; nxt[En] = head[u]; head[u] = En;
27     ++En; to[En] = u; nxt[En] = head[v]; head[v] = En;
28 }
29
30 void dfs(int u) {
31     siz[u] = 1;
32     for (int i=head[u]; i; i=nxt[i]) {
33         int v = to[i];
34         if (v == fa[u]) continue;
35         fa[v] = u;
36         dfs(v);
37         siz[u] += siz[v];
38         if (!son[u] || siz[son[u]] < siz[v]) son[u] = v;
39     }
40 }
41
42 void add(int u) {
43     cnt[col[u]] ++;
44     if (cnt[col[u]] > Mx) Mx = cnt[col[u]], Sum = col[u];
45     else if (cnt[col[u]] == Mx) Sum += col[u];
46 }
47 void Calc(int u) {
48     add(u);
49     for (int i=head[u]; i; i=nxt[i])
50         if (to[i] != fa[u]) Calc(to[i]);
51 }
52 void Clear(int u) {
53     cnt[col[u]] --;
54     for (int i=head[u]; i; i=nxt[i])
55         if (to[i] != fa[u]) Clear(to[i]);
56 }
57
58 void solve(int u,bool c) {
59     for (int i=head[u]; i; i=nxt[i])
60         if (to[i] != fa[u] && to[i] != son[u]) solve(to[i], 0);
61     if (son[u]) solve(son[u], 1);
62     add(u);
63     for (int i=head[u]; i; i=nxt[i])
64         if (to[i] != fa[u] && to[i] != son[u]) Calc(to[i]);
65     ans[u] = Sum;
66     if (!c) Clear(u), Mx = 0, Sum = 0;
67 }
68
69 int main() {
70     int n = read();
71     for (int i=1; i<=n; ++i) col[i] = read();
72     for (int i=1; i<n; ++i) {
73         int u = read(), v = read();
74         add_edge(u, v);
75     }
76     dfs(1);
77     solve(1, 1);
78     for (int i=1; i<=n; ++i) printf("%I64d ",ans[i]);
79     return 0;
80 }

原文地址:https://www.cnblogs.com/mjtcn/p/9711168.html

时间: 2024-10-08 15:16:08

CF 600 E. Lomsat gelral的相关文章

CF 600 E Lomsat gelral —— 树上启发式合并

题目:http://codeforces.com/contest/600/problem/E 看博客:https://blog.csdn.net/blue_kid/article/details/82192641 https://blog.csdn.net/clove_unique/article/details/60772212 还是不太明白复杂度... 代码如下: #include<iostream> #include<cstdio> #include<cstring&g

Codeforces 600E Lomsat gelral (Dsu On the Tree)

题目链接 Lomsat gelral 占坑--等深入理解了再来补题解-- 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 7 typedef long long LL; 8 9 const int N = 600010; 10 11 int n; 12 int cc[N], col[N], sz[N], son[N];

【CF600E】 Lomsat gelral

CF600E Lomsat gelral Solution 考虑一下子树的问题,我们可以把一棵树的dfn序搞出来,那么子树就是序列上的一段连续的区间. 然后就可以莫队飞速求解了. 但是这题还有\(\Theta(nlog_n)\)的做法.能有\(\Theta(n\sqrt{n})\)的做法要什么\(logn\)的 考虑\(dsu\ on\ tree\),与莫队没有任何区别. 如果不会的话,请自行跳转小Z的袜子并且切掉. 代码实现 #include<stdio.h> #include<std

【题解】Lomsat gelral [CF600E]

[题解]Lomsat gelral [CF600E] [前言] 写完 \(\text{Dsu on tree}\) 后大致浏览了网上的题解,常见做法有以下几种: \(\text{Dsu on tree}\)(占大多数,毕竟是板子) 线段树合并(空间巨大) \(O(n\sqrt{n}logn)\) 的 \(\text{DFS}\) 序 \(+\) \(sb\) 暴力莫队(时间巨大) \(O(n\sqrt{n})\) 的 \(\text{DFS}\) 序 \(+\) 回滚莫队(效率一般) 但就是没找

CF 600E. Lomsat gelral(dsu on tree)

解题思路 \(dsu\) \(on\) \(tree\)的模板题.暴力而优雅的算法,轻儿子的信息暴力清空,重儿子的信息保留,时间复杂度\(O(nlogn)\) 代码 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<set> using namespace std; const int

Codeforces 600E. Lomsat gelral(Dsu on tree学习)

题目链接:http://codeforces.com/problemset/problem/600/E n个点的有根树,以1为根,每个点有一种颜色.我们称一种颜色占领了一个子树当且仅当没有其他颜色在这个子树中出现得比它多.求占领每个子树的所有颜色之和. 我们都知道可以$BST$启发式合并从而完美${O(nlogn^{2})}$,这太丑陋了. 那么$Dsu~~on~~tree$是在干啥呢? 找出树中每一个节点的重儿子,统计答案的时候优先进入每一个点的所有轻儿子,之后再进入重儿子,目的是保留重儿子所

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

(题面来自luogu) 题意翻译 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. ci <= n <= 1e5 树上启发式合并裸题.统计时先扫一遍得到出现次数最大值,然后再扫一遍看哪个颜色的出现次数与mxCnt相等.注意用一个bool数组判重,清空轻儿子贡献时要顺手把bool数组也打成false. 代码: #include <iostream> #include <cstdio> #include <cctype&

CodeForces 600E Lomsat gelral(线段树合并)

题目链接:http://codeforces.com/problemset/problem/600/E 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

600E - Lomsat gelral(找子树多颜色问题)(入门)

题:https://codeforces.com/problemset/problem/600/E 题意:一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和,对于每个结点都输出答案. 分析:考虑暴力算法,对于每个节点只是清空计数数组,再对其子树颜色进行统计,复杂度o(n^2); 接着我们发现最后一个子树的清空是必要的,所以我们把重儿子当作这个子树,就可以让复杂度降为o(nlogn)级别: #include<bits/stdc++.h> using n