题面

题解

看到网上写了很多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. 快速 IO

    IO 的进化史 cin和cout 刚开始学的时候,老师叫我们用 cin 和 cout 大概是因为这最简单吧 cin>>x; cout<<x scanf和printf 学到函数了 ...

  2. DirectX11 With Windows SDK--19(Dev) 编译Assimp并加载模型、新的Effects框架

    前言 注意:这一章进行了重写,对应教程Dev分支第19章的项目,在更新完后面的项目后会替换掉原来第19章的教程 在前面的章节中我们一直使用的是由代码生成的几何模型,但现在我们希望能够导入模型设计师生成 ...

  3. Node.js精进(4)——事件触发器

    Events 是 Node.js 中最重要的核心模块之一,很多模块都是依赖其创建的,例如上一节分析的流,文件.网络等模块. 比较知名的 Express.KOA 等框架在其内部也使用了 Events 模 ...

  4. 图片64base转码与解码

    场景一:图片转码成base64,传输,接收后解码成png等格式图片 import base64 # 读取图片,转换为base64编码格式 with open("F:\Archer\pictu ...

  5. 全国气象数据/降雨量分布数据/太阳辐射数据/NPP净初级生产力数据/植被覆盖度数据

    ​        气象数据一直是一个价值较高的数据,它被广泛用于各个领域的研究当中.气象数据包括有气温.气压.相对湿度.降水.蒸发.风向风速.日照等多种指标,但是包含了这些全部指标的气象数据却较难获取 ...

  6. 强化学习-学习笔记12 | Dueling Network

    这是价值学习高级技巧第三篇,前两篇主要是针对 TD 算法的改进,而Dueling Network 对 DQN 的结构进行改进,能够大幅度改进DQN的效果. Dueling Network 的应用范围不 ...

  7. 智能指针思想实践(std::unique_ptr, std::shared_ptr)

    1 smart pointer 思想 ​ 个人认为smart pointer实际上就是一个对原始指针类型的一个封装类,并对外提供了-> 和 * 两种操作,使得其能够表现出原始指针的操作行为. ​ ...

  8. 初始化二维列表时使用[ [0]* N ] * K会出现的问题

    声明二维列表使用[ [0]* N ] * K会出现的问题 初始化二维列表时使用[ [0]* N ] * K创建,外层列表的每一个元素地址相同: 创造了一个二维列表: 修改其中的一个元素a[1][1], ...

  9. CMU15445 (Fall 2019) 之 Project#4 - Logging & Recovery 详解

    前言 这是 Fall 2019 的最后一个实验,要求我们实现预写式日志.系统恢复和存档点功能,这三个功能分别对应三个类 LogManager.LogRecovery 和 CheckpointManag ...

  10. 如何使用API接口批量查询图书信息?

    之前小编讲过在Excel表格中根据ISBN查询图书信息可以使用我们的图书查询公式,但偶然间发现少部分书籍由于年份久远导致查不出来,今天小编就教给大家另一种查询图书信息的方式,即通过API接口返回的JS ...