题面

题解

看到网上写了很多DSU和线段树合并的题解,笔者第一次做也是用的线段树合并,但在原题赛的时候却怕线段树合并调不出来,于是就用了更好想更好调的莫队。

这里笔者就说说莫队怎么做吧。

我们可以通过 dfs 序把点都拍到序列上,然后每个点的主导编号和就相当于询问一段区间的主导编号和,并且这样的询问刚好 n 个。

那么维护两个数组和一个变量

  • C

    [

    i

    ]

    C[i]

    C[i]:第

    i

    i

    i 种颜色的出现次数

  • S

    m

    [

    i

    ]

    Sm[i]

    Sm[i]:出现

    i

    i

    i 次的颜色编号和

  • a

    n

    s

    ans

    ans:出现的最多次数是几次(即实际的答案是

    S

    m

    [

    a

    n

    s

    ]

    Sm[ans]

    Sm[ans],这样方便维护些)

当我们的序列中新加入一个点时(我们已经开始跑莫队了),设这个点的颜色为

c

o

l

col

col ,那么

C

[

c

o

l

]

C[col]

C[col] 很好维护吧,

S

m

[

.

.

.

]

Sm[...]

Sm[...] 也很好维护吧,那么我们需要证明一个结论:

a

n

s

ans

ans 每次变动的幅度最多为 1。

其实很好证,由于每次

C

[

c

o

l

]

C[col]

C[col] 最多改 1,因此

S

m

[

.

.

.

]

Sm[...]

Sm[...] 只在长度为 2 的范围内有变动,其中一个清零的话,另一个肯定会有值,而

a

n

s

ans

ans 的值只取决于最大的有值的

S

m

[

.

.

.

]

Sm[...]

Sm[...] ,因此由于最大的

S

m

Sm

Sm 最多变动 1,所以

a

n

s

ans

ans 也最多变动 1。在脑袋里模拟一下也会理解的。

具体怎么操作可以看代码的

i

n

s

(

)

ins()

ins() 和

d

e

l

(

)

del()

del() 函数。

CODE

#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define LL long long
#define ENDL putchar('\n')
#define DB double
#define lowbit(x) (-(x) : (x))
LL read() {
LL f = 1,x = 0;char s = getchar();
while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
return x * f;
}
const int MOD = 1000000007;
int n,m,i,j,s,o,k,sq;
vector<int> g[MAXN];
int dfn[MAXN],rr[MAXN],cnt,id[MAXN];
int cl[MAXN];
void dfs(int x,int fa) {
dfn[x] = ++ cnt; id[cnt] = x;
for(int i = 0;i < (int)g[x].size();i ++) {
if(g[x][i] != fa) {
dfs(g[x][i],x);
}
}
rr[x] = cnt;
return ;
}
struct it{
int l,r,id;
}q[MAXN];
bool cmp(it a,it b) {
if(a.l/sq != b.l/sq) return a.l < b.l;
return a.r < b.r;
}
int L,R,c[MAXN],ans;
LL sm[MAXN],as[MAXN];
void ins(int x) { // x 是点编号
int col = cl[x];
sm[c[col]] -= col;
c[col] ++;
sm[c[col]] += col;
if(sm[ans+1] > 0) ans ++;
else if(!sm[ans]) ans --;
return ;
}
void del(int x) {
int col = cl[x];
sm[c[col]] -= col;
c[col] --;
sm[c[col]] += col;
if(sm[ans+1] > 0) ans ++;
else if(!sm[ans]) ans --;
return ;
}
int main() {
n = read();
sq = (int)sqrt((DB)n);
for(int i = 1;i <= n;i ++) cl[i] = read();
for(int i = 1;i < n;i ++) {
s = read();o = read();
g[s].push_back(o);
g[o].push_back(s);
}
dfs(1,0);
for(int i = 1;i <= n;i ++) {
q[i].id = i;
q[i].l = dfn[i];q[i].r = rr[i];
}
sort(q + 1,q + 1 + n,cmp);
L = 1,R = 0;
for(int i = 1;i <= n;i ++) {
int l = q[i].l,r = q[i].r;
while(L > l) ins(id[-- L]);
while(R < r) ins(id[++ R]);
while(L < l) del(id[L ++]);
while(R > r) del(id[R --]);
as[q[i].id] = sm[ans];
}
for(int i = 1;i <= n;i ++) {
printf("%lld ",as[i]);
}ENDL;
return 0;
}

CF600E Lomsat gelral (dfs序+莫队)的更多相关文章

  1. hdu 4358 Boring counting dfs序+莫队+离散化

    Boring counting Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 98304/98304 K (Java/Others) ...

  2. hdu 4358 Boring counting 离散化+dfs序+莫队算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4358 题意:以1为根节点含有N(N <= 1e5)个结点的树,每个节点有一个权值(weight ...

  3. Codeforces 375D - Tree and Queries(dfs序+莫队)

    题目链接:http://codeforces.com/contest/351/problem/D 题目大意:n个数,col[i]对应第i个数的颜色,并给你他们之间的树形关系(以1为根),有m次询问,每 ...

  4. Codeforces 375D Tree and Queries(DFS序+莫队+树状数组)

    题目链接  Tree and Queries 题目大意  给出一棵树和每个节点的颜色.每次询问$vj, kj$ 你需要回答在以$vj$为根的子树中满足条件的的颜色数目, 条件:具有该颜色的节点数量至少 ...

  5. HDU 4358 Boring counting dfs序+莫队算法

    题意:N个节点的有根树,每个节点有一个weight.有Q个查询,问在以u为根的子树中,有恰好出现了K次的weight有多少种. 这是第一次写莫队算法,之前也只是偶有耳闻. 看了别人的代码打的,还是贴上 ...

  6. codeforces 375D . Tree and Queries 启发式合并 || dfs序+莫队

    题目链接 一个n个节点的树, 每一个节点有一个颜色, 1是根节点. m个询问, 每个询问给出u, k. 输出u的子树中出现次数大于等于k的颜色的数量. 启发式合并, 先将输入读进来, 然后dfs完一个 ...

  7. CF600E Lomsat gelral(dsu on tree)

    dsu on tree跟冰茶祭有什么关系啊喂 dsu on tree的模板题 思想与解题过程 类似树链剖分的思路 先统计轻儿子的贡献,再统计重儿子的贡献,得出当前节点的答案后再减去轻儿子对答案的贡献 ...

  8. CF600E Lomsat gelral 和 CF741D Dokhtar-kosh paths

    Lomsat gelral 一棵以\(1\)为根的树有\(n\)个结点,每个结点都有一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号(若有数量一样的,则求编号和). \(n \le 10^ ...

  9. CF600E Lomsat gelral 【线段树合并】

    题目链接 CF600E 题解 容易想到就是线段树合并,维护每个权值区间出现的最大值以及最大值位置之和即可 对于每个节点合并一下两个子节点的信息 要注意叶子节点信息的合并和非叶节点信息的合并是不一样的 ...

随机推荐

  1. synchronized下的 i+=2 和 i++ i++执行结果居然不一样

    起因 逛[博客园-博问]时发现了一段有意思的问题: 问题链接:https://q.cnblogs.com/q/140032/ 这段代码是这样的: import java.util.concurrent ...

  2. 开发工具-Redis Desktop Manager下载地址

    更新记录 2022年6月10日 完善标题. 官方: https://github.com/uglide/RedisDesktopManager 免费打包版: https://github.com/le ...

  3. 慢到不能忍?别忍了,Ubuntu 21.10 APT 源修改为华为云镜像源

    更新记录 2022年4月15日:本文迁移自Panda666原博客,原发布时间:2021年3月29日. 2022年4月15日:将源改为华为云,华为云更方便.Ubuntu从20.04更新到21.10. 切 ...

  4. SAP Smart Form 无法通过程序自定义默认打印机问题解决

    *&---------------------------------------------------------------------* *& Form FRM_SET_PRI ...

  5. 建立QT工程的规范型,以及重要性

    当前管理开发多个项目,故名Projects 下一级目录,具体项目,故示例Project,根据实际情况自行取名 再下一级目录,有三个子目录 bin:生成的可执行文件或者动态链接库,build:编译源码时 ...

  6. rhel挂载本地光盘为yum源

    挂载光盘 mount /dev/sr0 /mnt/cdrom mkdir /mnt/cdrom 临时挂载 mount /dev/sr0 /mnt/cdrom 永久挂载光盘 mount -a 执行挂载 ...

  7. C语言-数据结构-结构体

    一.结构体的定义 数组(Array)是一组具有相同类型的数据的集合.但在实际的编程过程中,我们往往还需要一组类型不同的数据,例如对于学生信息登记表,姓名为字符串,学号为整数,年龄为整数,所在的学习小组 ...

  8. 记一次requests请求乱码的问题

    太懒了,直接说原因吧: 请求返回的内容含有emoji表情 我的解决办法是替换掉emoji字符: 安装库:pip install emoji 替换:emoji.demojize(CONTENT) 注意, ...

  9. 比起网易有数BI,也许这款数据可视化软件更适合你!

    有数BI是网易推出的面向企业客户的可视化敏捷BI产品.拥有数据填报和自助式商业智能分析产品,提供网页端和手机端应用,帮助客户快速实现数据填报.多维分析.大数据探索.实时大数据展示和成员分享. 山海鲸可 ...

  10. ApiDay002_01 正则表达式

    正则表达式 用于检测.测试字符串规则的表达式. 经常用于检测字符串是否符合特定的规则,在网站上经常用于检测用户输入数据是否符合规范: 检测 用户名 是否为 8~10 数字 英文(大小写) 检测 电话号 ...