With $Dsu \ on \ tree$ we can answer queries of this type:

How many vertices in the subtree of vertex $v$ has some property in $O (n \log n)$ time (for all of the queries)?

这题写的是轻重儿子(重链剖分)版本的 $Dsu \ on \ tree$

具体流程如下:

每次先递归计算轻儿子,再单独递归重儿子,计算完后轻儿子的一些信息需要删掉,但是重儿子的信息无需删除,如此出解,相当于是优化了暴力的多余部分

每个节点会作为轻儿子被计算,重链剖分上垂直有 $\log n$ 条链,故复杂度 $O (n \log n)$

代码

 #include <iostream>
#include <cstdio>
#include <cstring> using namespace std; typedef long long LL; const int MAXN = 1e05 + ;
const int MAXM = 1e05 + ;
const int MAXC = 1e05 + ; struct LinkedForwardStar {
int to; int next;
} ; LinkedForwardStar Link[MAXM << ];
int Head[MAXN]= {};
int size = ; void Insert (int u, int v) {
Link[++ size].to = v;
Link[size].next = Head[u]; Head[u] = size;
} int N;
int colour[MAXN]; int son[MAXN]= {};
int subsize[MAXN]= {};
void DFS (int root, int father) {
son[root] = - ;
subsize[root] = ;
for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father)
continue;
DFS (v, root);
subsize[root] += subsize[v];
if (son[root] == - || subsize[v] > subsize[son[root]])
son[root] = v;
}
}
int vis[MAXN]= {};
int total[MAXC]= {};
int maxv = ;
LL sum = ;
void calc (int root, int father, int delta) { // 统计答案
total[colour[root]] += delta;
if (delta > && total[colour[root]] >= maxv) {
if (total[colour[root]] > maxv)
sum = , maxv = total[colour[root]];
sum += colour[root];
}
for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father || vis[v])
continue;
calc (v, root, delta);
}
}
LL answer[MAXN]= {};
void Solve (int root, int father, int type) { // type表示是不是重儿子信息
for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father || v == son[root])
continue;
Solve (v, root, );
}
if (~ son[root])
Solve (son[root], root, ), vis[son[root]] = ;
calc (root, father, );
answer[root] = sum;
if (~ son[root])
vis[son[root]] = ;
if (! type) // 如果是轻儿子信息就需删除
calc (root, father, - ), maxv = sum = ;
} int getnum () {
int num = ;
char ch = getchar (); while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = (num << ) + (num << ) + ch - '', ch = getchar (); return num;
} int main () {
N = getnum ();
for (int i = ; i <= N; i ++)
colour[i] = getnum ();
for (int i = ; i < N; i ++) {
int u = getnum (), v = getnum ();
Insert (u, v), Insert (v, u);
}
DFS (, ), Solve (, , );
for (int i = ; i <= N; i ++) {
if (i > )
putchar (' ');
printf ("%lld", answer[i]);
}
puts (""); return ;
} /*
4
1 2 3 4
1 2
2 3
2 4
*/ /*
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
*/

Codeforces 600E - Lomsat gelral 「$Dsu \ on \ tree$模板」的更多相关文章

  1. Codeforces 600E Lomsat gelral(dsu on tree)

    dsu on tree板子题.这个trick保证均摊O(nlogn)的复杂度,要求资瓷O(1)将一个元素插入集合,清空集合时每个元素O(1)删除.(当然log的话就变成log^2了) 具体的,每次先遍 ...

  2. Codeforces 600E - Lomsat gelral(树上启发式合并)

    600E - Lomsat gelral 题意 给出一颗以 1 为根的树,每个点有颜色,如果某个子树上某个颜色出现的次数最多,则认为它在这课子树有支配地位,一颗子树上,可能有多个有支配的地位的颜色,对 ...

  3. Codeforces.600E.Lomsat gelral(dsu on tree)

    题目链接 dsu on tree详见这. \(Description\) 给定一棵树.求以每个点为根的子树中,出现次数最多的颜色的和. \(Solution\) dsu on tree模板题. 用\( ...

  4. Codeforces 600E Lomsat gelral (树上启发式合并)

    题目链接 Lomsat gelral 占坑……等深入理解了再来补题解…… #include <bits/stdc++.h> using namespace std; #define rep ...

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

    题目链接:http://codeforces.com/problemset/problem/600/E n个点的有根树,以1为根,每个点有一种颜色.我们称一种颜色占领了一个子树当且仅当没有其他颜色在这 ...

  6. codeforces 600E Lomsat gelral

    题面:codeforces600E 学习一下$dsu \ on \ tree$.. 这个东西可以处理很多无修改子树问题,复杂度通常为$O(nlogn)$. 主要操作是:我们先把整棵树链剖一下,然后每次 ...

  7. codeforces 600E. Lomsat gelral 启发式合并

    题目链接 给一颗树, 每个节点有初始的颜色值. 1为根节点.定义一个节点的值为, 它的子树中出现最多的颜色的值, 如果有多种颜色出现的次数相同, 那么值为所有颜色的值的和. 每一个叶子节点是一个map ...

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

  9. 【Codeforces】600E. Lomsat gelral

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

随机推荐

  1. 使用Arduino驱动基于ST7533芯片的TFT屏

    在合宙通信买了一个1.8寸的TFT屏,驱动芯片是ST7533,本来打算使用Air800直接驱动,但由于其他原因,放弃了.于是尝试使用arduino驱动,为了屏幕刷新速度更快,采用硬件SPI. 硬件连接 ...

  2. 插入排序的C、C++实现

    一.插入排序 有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法--插入排序法,插入排序的基本操作就是将一个数据插入到 ...

  3. [知乎]BAT占线

    黑色自有,蓝色全资收够,红色入股. https://www.zhihu.com/question/304396738/answer/547766603

  4. idea 导入项目后不能执行main方法

    点击右键,出来不能run/debug 项目分为多个mouel模块,很多模块进来后在idea中丢失了(暂时不知道原因) 我们需要做的就是把丢失的模块加进来 ctrl+alt+shift+s 快捷键  或 ...

  5. 一本通1625【例 1】反素数 Antiprime

    反素数 Antiprime 题目描述 原题来自:POI 2001 如果一个大于等于 1 的正整数 n,满足所有小于 n 且大于等于 1 的所有正整数的约数个数都小于 n 的约数个数,则 n 是一个反素 ...

  6. SpringMVC返回JSON方案

    SpringMVC已经大行其道.一般的,都是返回JSP视图.如果需要返回JSON格式,我们大都掌握了一些方法. 在ContentNegotiatingViewResolver之前,一般使用XmlVie ...

  7. subprocess 子进程模块

    subprocess子进程模块 import subprocess #Popen方法是用来执行系统命令的,直接把结果打印到终端了 res =subprocess.Popen(r'dir',shell= ...

  8. 【转】如何向XML内插入一个字符串片段

    转自:http://bbs.csdn.net/topics/190051229   5楼 string filepath = Server.MapPath("你的xml文件"); ...

  9. MT【104】高斯函数找周期

    分析:$t(n)=n-[\frac{n}{2}]-[\frac{n}{3}]-[\frac{n}{6}]$的周期为6,故 $\sum\limits_{n=1}^{2014}(n-t(n))=\sum\ ...

  10. Different between Telnet/SSH/FTP

    http://www.differencebetween.net/category/technology/protocols-formats/ Telnet vs SSH Secure Shell, ...