启发式合并最重要的思想就是指的是每次将小集合拷贝合并至大集合。
考虑每个元素的合并开销。对于合并次数最多的那个元素来说,它每合并一次,所在集合的规模扩大两倍,最多只会合并 logN 次,因而对于所有元素,至多插入set中NlogN次,时间复杂度就有上限 O(N∗logN∗logN)

现在主要是dsu on tree,它用来解决这样一类问题:统计树上一个节点的子树中具有某种特征的节点数。 基本上就是树上子树的统计问题。

但是dsu on tree也有一定的局限性:1.只能支持子树查询;2.不支持修改修改。

看例题来说:

D - Lomsat gelralCodeForces - 600E

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 subtree of vertex v more times than colour c. So it's possible that two or more colours will be dominating in the subtree of some vertex.

The subtree of vertex v is the vertex v and all other vertices that contains vertex v in each path to the root.

For each vertex v find the sum of all dominating colours in the subtree of vertex v.

Input

The first line contains integer n (1 ≤ n ≤ 105) — the number of vertices in the tree.

The second line contains n integers ci (1 ≤ ci ≤ n), ci — the colour of the i-th vertex.

Each of the next n - 1 lines contains two integers xj, yj (1 ≤ xj, yj ≤ n) — the edge of the tree. The first vertex is the root of the tree.

Output

Print n integers — the sums of dominating colours for each vertex.

Examples

Input
4
1 2 3 4
1 2
2 3
2 4
Output
10 9 3 4
Input
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
Output
6 5 4 3 2 3 3 1 1 3 2 2 1 2 3

题意:给定一个 n 个节点的树,对于每个子树,输出子树中出现次数最多的节点编号之和。(次数最多的编号有多个节点都要统计进去)。 
想法:最初的想法是对于每个点都跑一遍,暴力跑每个点的子树,然后记录下来答案,然后清空数组跑下一次,但是这样的话就时间复杂度就非常的高。
所以要优化一下,我们都知道每个点有子树的话,会有一个重子树(就是点相对最多的那颗子树)。所以我们先预处理一下找到所有节点重子树。
然后对于每科子树,我们先跑每颗子树的轻子树,跑完之后再跑重子树。在计算结果的时候,假设某一个点的儿子都已经被dfs过,统计这个点的答案。统计答案的过程中要calc当前这个点的子树,但是只calc它的轻链,重链不做。 
这样的话,就需要在dfs的过程中,如果当前点是它父亲的轻儿子,做完这个点之后就将影响消除;而如果这个点是它父亲的重儿子,则将这个点的影响保留。 
我们看下代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int maxn=1e5+;
int n,m;
int mx,big;
LL sum=;
LL ans[maxn];
int col[maxn],si[maxn],hson[maxn],cnt[maxn];
vector<int>G[maxn]; void findhson(int x,int fa)//找到所有的重儿子
{
si[x]=;
int len=G[x].size();
for(int i=;i<len;i++)
{
int t=G[x][i];
if(t!=fa)
{
findhson(t,x);
si[x]+=si[t];
if(si[t]>si[hson[x]])
hson[x]=t;
}
}
}
void cal(int x,int fa,int val)//计算的过程,就是不断递归求颜色的数量
{
cnt[col[x]]+=val;
if(cnt[col[x]]>mx)
{
sum=col[x];
mx=cnt[col[x]];
}
else if(cnt[col[x]]==mx)
sum+=col[x];
int len=G[x].size();
for(int i=;i<len;i++)
{
int t=G[x][i];
if(t!=fa && t!=big)
cal(t,x,val);
}
}
void dfs(int x,int fa,int flag)//flag作为标记,看是轻子树还是重子树
{
int len=G[x].size();
for(int i=;i<len;i++)//先跑轻子树
{
int t=G[x][i];
if(t!=fa && t!=hson[x])
dfs(t,x,);
}
if(hson[x])//再跑重子树
{
dfs(hson[x],x,);
big=hson[x];
}
cal(x,fa,);
big=;
ans[x]=sum;
if(!flag)//如果是轻子树的话,消除影响
{
cal(x,fa,-);
mx=;sum=;
}
}
int main()
{
sum=;big=;mx=;
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&col[i]);
int x,y;
for(int i=;i<n;i++)//双向边
{
scanf("%d %d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
findhson(,);
dfs(,,);
for(int i=;i<=n;i++)
{
if(i==)
printf("%lld",ans[i]);
else
printf(" %lld",ans[i]);
}
printf("\n");
return ;
}
 
 

启发式合并 CodeForces - 600E的更多相关文章

  1. 启发式合并CodeForces - 1009F

    E - Dominant Indices CodeForces - 1009F You are given a rooted undirected tree consisting of nn vert ...

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

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

  3. Codeforces - 600E 树上启发式合并

    题意:求每一个子树存在最多颜色的颜色代号和(可重复) 本题是离线统计操作,因此可以直接合并重儿子已达到\(O(nlogn)\)的复杂度 PS.不知道什么是启发式合并的可以这样感受一下:进行树链剖分,分 ...

  4. Educational Codeforces Round 2 E. Lomsat gelral 启发式合并map

    E. Lomsat gelral Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/600/prob ...

  5. CodeForces 958F3 Lightsabers (hard) 启发式合并/分治 多项式 FFT

    原文链接http://www.cnblogs.com/zhouzhendong/p/8835443.html 题目传送门 - CodeForces 958F3 题意 有$n$个球,球有$m$种颜色,分 ...

  6. codeforces 741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths(启发式合并)

    codeforces 741D Arpa's letter-marked tree and Mehrdad's Dokhtar-kosh paths 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...

  7. codeforces#1166F. Vicky's Delivery (Service并查集+启发式合并)

    题目链接: https://codeforces.com/contest/1166/problem/F 题意: 给出节点数为$n$,边数为$m$的图,保证每个点对都是互连的 定义彩虹路:这条路经过$k ...

  8. codeforces 600E E. Lomsat gelral (线段树合并)

    codeforces 600E E. Lomsat gelral 传送门:https://codeforces.com/contest/600/problem/E 题意: 给你一颗n个节点的树,树上的 ...

  9. Codeforces 1455G - Forbidden Value(map 启发式合并+DP)

    Codeforces 题面传送门 & 洛谷题面传送门 首先这个 if 与 end 配对的结构显然形成一个树形结构,考虑把这棵树建出来,于是这个程序的结构就变为,对树进行一遍 DFS,到达某个节 ...

随机推荐

  1. 洛谷 P3952 时间复杂度【模拟】

    把No写成NO,WA了一发-- 现在看这题也不难-- 用一个栈,记一下前面F的字母,是否合法,合法的有多长,每次入栈弹栈即可 #include<iostream> #include< ...

  2. poj 1815 Friendship【最小割】

    网络流的题总是出各种奇怪的错啊--没写过邻接表版的dinic,然后bfs扫到t点不直接return 1就会TTTTTLE-- 题目中的操作是"去掉人",很容易想到拆点,套路一般是( ...

  3. 3-2 -------WERTYU------题挺水的

    //题目的意思就是-----键盘上面你输入一个字符,就要输出该字符左边的字符. //空格和回车原样输出. #include<stdio.h> int main() { char a[]={ ...

  4. Logstash读取文本信息并写入到ES

    Logstash读取文本信息并写入到ES 前提是ELK安装没问题 进入到logstash安装目录下的bin目录(我的logstash安装目录:/usr/local/) [root@es1 bin]# ...

  5. Code:Blocks 中文乱码问题原因分析和解决方法

    下面说说修改的地方. 1.修改源文件保存编码在:settings->Editor->gernal settings 看到右边的Encoding group Box了吗?如下图所示: Use ...

  6. _bzoj1036 [ZJOI2008]树的统计Count【树链剖分】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1036 保存模版. 执行qmax与qsum操作,往上爬的时候最开始的代码出了点小问题,往上爬的 ...

  7. That Nice Euler Circuit UVALive - 3263 || 欧拉公式

    欧拉定理: 简单多面体的顶点数V.棱数E及面数F间有关系有著名的欧拉公式:V-E+F=2. 设G为任意的连通的平面图,则v-e+f=2,v是G的顶点数,e是G的边数,f是G的面数.(引) 证明(?) ...

  8. Android Dialogs(3)警示Dialog教程[创建,单选,复选,自定义]等等

    本节内容 1. Building an Alert Dialog 2. Adding buttons 3. Adding a list 4. Adding a persistent multiple- ...

  9. 413 Arithmetic Slices 等差数列划分

    如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列.例如,以下数列为等差数列:1, 3, 5, 7, 97, 7, 7, 73, -1, -5, -9以下数列不是等差数列. ...

  10. Netflix正式开源其API网关Zuul 2--转

    微信公众号:聊聊架构 5 月 21 日,Netflix 在其官方博客上宣布正式开源微服务网关组件 Zuul 2.Netflix 公司是微服务界的楷模,他们有大规模生产级微服务的成功应用案例,也开源了相 ...