启发式合并 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,到达某个节 ...
随机推荐
- bzoj 1913: [Apio2010]signaling 信号覆盖【旋转卡壳(?)】
参考:https://blog.csdn.net/qpswwww/article/details/45334033 讲的很清楚 做法比较像旋转卡壳但是具体是不是我也不清楚.. 首先知道只要求出每种方案 ...
- 洛谷 P2762 太空飞行计划问题 【最大权闭合子图+最小割】
--一道难在读入的题. 最后解决方案直接getline一行然后是把读优拆掉放进函数,虽然很丑但是过了. 然后就是裸的最大权闭合子图了,把仪器当成负权点向t连流量为其价格的边,s向实验连流量为实验报酬的 ...
- [BZOJ1381]Knights
Description 在一个N*N的棋盘上,有些小方格不能放骑士,棋盘上有若干骑士,任一个骑士不在其它骑士的攻击范围内,请输出最多可以放多少个骑士. 骑士攻击的点如中国象棋中的马,可以攻击8个点. ...
- shell脚本从入门到精通
阿里云大学 shell脚本从入门到精通 第1 章 : shell脚本编程-变量-算术表达式-判断语句-if分支语句 第2 章 : case-for-While-双括号-循环嵌套-break-conti ...
- Frequency of String CodeForces - 963D
http://codeforces.com/contest/963/problem/D 题解:https://www.cnblogs.com/Blue233333/p/8881614.html 记M为 ...
- 条件DP UVA 672 Gangsters
题目传送门 题意:n个歹徒进饭店,可变化宽度的门,范围[0, k],每个歹徒进门在ti时间进门,身材si,进去后有pi的成功值,问最大的成功值 分析:首先按照进门时间排序,dp[i][j] 表示第i个 ...
- 题解报告:hdu 2062 Subset sequence
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2062 Problem Description 考虑集合An = {1,2,...,n}. 例如,A1 ...
- Objective-c单例模式的正确写法--用dispatch 线程安全
单例模式在iOS开发中可能算是最常用的模式之一了,但是由于oc本身的语言特性,想要写一个正确的单例模式相对来说比较麻烦,这里我就抛砖引玉来聊一聊iOS中单例模式的设计思路.关于单例模式更多的介绍请参考 ...
- JMeter(十一)内存溢出解决方法
使用jmeter进行压力测试时遇到一段时间后报内存溢出outfmenmory错误,导致jmeter卡死了,先尝试在jmeter.bat中增加了JVM_ARGS="-Xmx2048m -Xms ...
- Codeforces Round #179 (Div. 1)
A 直接线段树过的 两遍 貌似大多是标记过的..注意long long #include <iostream> #include <cstdio> #include <c ...