启发式合并 CodeForces - 600E
启发式合并最重要的思想就是指的是每次将小集合拷贝合并至大集合。
考虑每个元素的合并开销。对于合并次数最多的那个元素来说,它每合并一次,所在集合的规模扩大两倍,最多只会合并 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
4
1 2 3 4
1 2
2 3
2 4
10 9 3 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
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的更多相关文章
- 启发式合并CodeForces - 1009F
E - Dominant Indices CodeForces - 1009F You are given a rooted undirected tree consisting of nn vert ...
- Codeforces 600E - Lomsat gelral(树上启发式合并)
600E - Lomsat gelral 题意 给出一颗以 1 为根的树,每个点有颜色,如果某个子树上某个颜色出现的次数最多,则认为它在这课子树有支配地位,一颗子树上,可能有多个有支配的地位的颜色,对 ...
- Codeforces - 600E 树上启发式合并
题意:求每一个子树存在最多颜色的颜色代号和(可重复) 本题是离线统计操作,因此可以直接合并重儿子已达到\(O(nlogn)\)的复杂度 PS.不知道什么是启发式合并的可以这样感受一下:进行树链剖分,分 ...
- 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 ...
- CodeForces 958F3 Lightsabers (hard) 启发式合并/分治 多项式 FFT
原文链接http://www.cnblogs.com/zhouzhendong/p/8835443.html 题目传送门 - CodeForces 958F3 题意 有$n$个球,球有$m$种颜色,分 ...
- 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 题意 给出一棵树,每条边上有一个字符,字符集大小只 ...
- codeforces#1166F. Vicky's Delivery (Service并查集+启发式合并)
题目链接: https://codeforces.com/contest/1166/problem/F 题意: 给出节点数为$n$,边数为$m$的图,保证每个点对都是互连的 定义彩虹路:这条路经过$k ...
- codeforces 600E E. Lomsat gelral (线段树合并)
codeforces 600E E. Lomsat gelral 传送门:https://codeforces.com/contest/600/problem/E 题意: 给你一颗n个节点的树,树上的 ...
- Codeforces 1455G - Forbidden Value(map 启发式合并+DP)
Codeforces 题面传送门 & 洛谷题面传送门 首先这个 if 与 end 配对的结构显然形成一个树形结构,考虑把这棵树建出来,于是这个程序的结构就变为,对树进行一遍 DFS,到达某个节 ...
随机推荐
- 【180】IDL 读写 HDF 文件
HDF(Hierarchical Data Formats)数据格式由 NCSA 开发.HDF 提供了大量的数据模式,包括多维数组.表格.图像.注解和调色板.在下面的章节中,将描述 HDF 科学数据系 ...
- Java 支持JavaScript脚本计算
Java支持了JavaScript脚本的执行计算能力: import javax.script.Invocable; import javax.script.ScriptEngine; import ...
- Unity3d 应用系统分析
- Jquery 之deferred
一.概述 在jquery中有种对象称之为延时对象,可以由 http请求方法$.get(), $.ajax(), $.post() 产生, 内置方法如下 也可以有jquery的延时方法 $.when( ...
- IE兼容之中文汉字请求乱码-network
IE兼容之中文汉字请求乱码 IE控制台报错: IE网络报错: 解决方法: encodeURI('--- @ -- 子卿 -'); // "---%20@%20--%20%E5%AD%90%E ...
- 《windows核心编程系列》十五谈谈windows线程栈
谈谈windows线程栈. 当系统创建线程时会为线程预订一块地址空间区域,注意仅仅是预订.默认情况下预定的这块区域的大小是1MB,虽然预订这么多,但是系统并不会给全部区域调拨物理存储器.默认情况下,仅 ...
- BZOJ2333 棘手的操作
Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 x ...
- 移动游戏By HYJ
暴力求SG函数即可,记忆化贼方便 /*program from Wolfycz*/ #include<cmath> #include<cstdio> #include<c ...
- 暑期训练狂刷系列——Hdu 3506 Largest Rectangle in a Histogram (单调栈)
题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=1506 题目大意: 给出一个数列An,问以Ai为最小值的区间内有多少个元素? 解题思路: 手动模拟一个 ...
- HDU 6096 树套树
思路: 网上的题解有AC自动机的,有trie树的,还有(乱搞?)的 首先把输入的那n个串按照字典序排序, 把n个串翻转以后再按照字典序排序 这样我们发现, 查的前缀在字典序排序后是一段区间, 查的后缀 ...