题目链接:http://codeforces.com/problemset/problem/600/E


n个点的有根树,以1为根,每个点有一种颜色。我们称一种颜色占领了一个子树当且仅当没有其他颜色在这个子树中出现得比它多。求占领每个子树的所有颜色之和

我们都知道可以$BST$启发式合并从而完美${O(nlogn^{2})}$,这太丑陋了。

那么$Dsu~~on~~tree$是在干啥呢?

找出树中每一个节点的重儿子,统计答案的时候优先进入每一个点的所有轻儿子,之后再进入重儿子,目的是保留重儿子所在子树的信息。

处理完当前点的所有儿子的子树之后开始处理自己。

先统计以当前点为根的子树不经过重儿子的所有点的影响${O(size[x]-size[hson[x]])}$

如果这个点是轻儿子则需要暴力删除这棵子树所带来的影响${O(size[x])}$,这也正是先进入轻儿子的原因,可以保留重儿子的信息。

考虑复杂度为什么正确:

  不妨想想一个点被反复计算了多少次?是不是${O(这个点到根的轻边条树)}$,这个东西是${O(logn)}$级别的。

最终复杂度:${O(nlogn)}$


 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
#define maxn 300100
#define llg long long
#define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
llg n,m,hson[maxn],size[maxn],ans[maxn],c[maxn],cnt[maxn],sum,mx,S;
vector<llg>a[maxn]; inline llg getint()
{
llg w=,q=; char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar(); if(c=='-') q=,c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar(); return q ? -w : w;
} void init()
{
llg x,y;
cin>>n;
for (llg i=;i<=n;i++) c[i]=getint();
for (llg i=;i<n;i++)
{
x=getint(),y=getint();
a[x].push_back(y),a[y].push_back(x);
}
} void find_hson(llg x,llg fa)
{
size[x]=;
llg w=a[x].size(),v;
for (llg i=;i<w;i++)
{
v=a[x][i];
if (v==fa) continue;
find_hson(v,x);
size[x]+=size[v];
if (size[v]>size[hson[x]]) hson[x]=v;
}
} void calc(llg x,llg fa,llg val)
{
cnt[c[x]]+=val;
if (cnt[c[x]]>mx) sum=c[x],mx=cnt[c[x]];
else
{
if (cnt[c[x]]==mx) sum+=c[x];
}
llg w=a[x].size(),v;
for (llg i=;i<w;i++)
{
v=a[x][i];
if (v==fa || v==S) continue;
calc(v,x,val);
}
} void dfs(llg x,llg fa,llg t)
{
llg w=a[x].size(),v;
for (llg i=;i<w;i++)
{
v=a[x][i];
if (v==fa || v==hson[x]) continue;
dfs(v,x,-);
}
if (hson[x]) dfs(hson[x],x,),S=hson[x];
calc(x,fa,); S=;
ans[x]=sum;
if (t==-) calc(x,fa,-),mx=sum=;
} int main()
{
yyj("tree");
init();
find_hson(,);
dfs(,,);
for (llg i=;i<=n;i++) printf("%lld ",ans[i]);
return ;
}

Codeforces 600E. Lomsat gelral(Dsu on tree学习)的更多相关文章

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

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

  2. CF 600E. Lomsat gelral(dsu on tree)

    解题思路 \(dsu\) \(on\) \(tree\)的模板题.暴力而优雅的算法,轻儿子的信息暴力清空,重儿子的信息保留,时间复杂度\(O(nlogn)\) 代码 #include<iostr ...

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

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

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

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

  5. Codeforces 600E - Lomsat gelral 「$Dsu \ on \ tree$模板」

    With $Dsu \ on \ tree$ we can answer queries of this type: How many vertices in the subtree of verte ...

  6. 【CodeForces】600 E. Lomsat gelral (dsu on tree)

    [题目]E. Lomsat gelral [题意]给定n个点的树,1为根,每个点有一种颜色ci,一种颜色占领一棵子树当且仅当子树内没有颜色的出现次数超过它,求n个答案——每棵子树的占领颜色的编号和Σc ...

  7. codeforces 600E Lomsat gelral

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

  8. cf600E. Lomsat gelral(dsu on tree)

    题意 题目链接 给出一个树,求出每个节点的子树中出现次数最多的颜色的编号和 Sol dsu on tree的裸题. 一会儿好好总结总结qwq #include<bits/stdc++.h> ...

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

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

随机推荐

  1. python中的logger模块

    logger 提供了应用程序可以直接使用的接口handler将(logger创建的)日志记录发送到合适的目的输出filter提供了细度设备来决定输出哪条日志记录formatter决定日志记录的最终输出 ...

  2. 深度点评五种常见WiFi搭建方案

    总结十年无线搭建经验,针对企业常见的五种办公室无线网络方案做个简要分析,各种方案有何优劣,又适用于那种类型的企业. 方案一:仅路由器或AP覆盖 简述:使用路由器或AP覆盖多个无线盲区,多个AP的部署实 ...

  3. GLSL写vertex shader和fragment shader

    0.一般来说vertex shader处理顶点坐标,然后向后传输,经过光栅化之后,传给fragment shader,其负责颜色.纹理.光照等等. 前者处理之后变成裁剪坐标系(三维),光栅化之后一般认 ...

  4. ConvertUtils.register(new DateConverter(null), java.util.Date.class)使用

    在我们使用BeanUtils.copyProperties(dest,orig)将一个类的属性赋值给另一个类的时候 如果类中存在 Date类型的转换可能会报"no value specifi ...

  5. 栈的压入和弹出序列(剑指Offer)

    输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一 ...

  6. kivy Properties

    Introduction to Properties¶ Properties are an awesome way to define events and bind to them. Essenti ...

  7. Django基础(10): URL重定向的HttpResponseDirect, redirect和reverse的用法详解

    利用django开发web应用, 我们经常需要进行URL重定向,有时候还需要给URL传递额外的参数.比如用户添加文章完成后需要转到文章列表或某篇文章详情.因此熟练掌握HttpResponseDirec ...

  8. Linux下Keepalived安装与配置

    一.简介 负载平衡是一种在真实服务器集群中分配IP流量的方法,可提供一个或多个高度可用的虚拟服务.在设计负载均衡拓扑时,重要的是要考虑负载均衡器本身的可用性以及它背后的真实服务器.用C编写的类似于la ...

  9. Linux维护常用命令

    1.查看Linux占用内存/CPU最多的进程 可以使用以下命令查使用内存最多的10个进程 #ps -aux | sort -k4nr | head -n 10可以使用以下命令查使用CPU最多的10个进 ...

  10. topcoder srm list

    300 305 310 315 320 325 330 335 340 350 360 370 380 390 400 410 415 420 425 430 435 440 445 450 455 ...