题面

题解

看到网上写了很多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. Docker容器手动安装oracle19C

    Docker容器手动安装oracle19C docker容器体积小,与宿主机共用内核参数,因此修改宿主机的内核参数即是修改容器的内核参数 1.修改宿主机内核参数 [root@localhost ~]# ...

  2. JavaGUI——Java图形用户界面

    1.Java GUI 概述 GUI(Graphical User Interface,简称 GUI,图形用户界面)是指采用图形方式显示的计算机操作用户界面,与早期计算机使用的命令行界面相比,图形界面对 ...

  3. SAP OOALV- 合计

    TYPES: BEGIN OF ty_mara, srno LIKE adrc-name1, " Storing the total text matnr LIKE mara-matnr, ...

  4. 合宙Air32F103CBT6开发板上手报告

    2022年6月初合宙新上市了 Air32F103 系列 MCU, 市面上 STM32F103 的克隆军队又增加了新的一员. 这次不知道是哪家的贴牌, 分 Air32F103CBT6 和 Air32F1 ...

  5. ansible环境安装及数据恢复

    配置免密登录服务器及下载备份文件#!/bin/bash BACKUP=192.168.30.233 #一行写一个IP BACKUP_PASSWD="lxzl_root*#2021" ...

  6. Python基础教程:模块重载的五种方法

    环境准备 新建一个 foo 文件夹,其下包含一个 bar.py 文件 $ tree foo foo └── bar.py 0 directories, 1 file bar.py 的内容非常简单,只写 ...

  7. SSRS筛选器的IN运算(即包含于)用法

    筛选器的IN运算,在Microsoft的官网上没像样儿的例子,不好设置,很容易错 Microsoft上的文档:https://docs.microsoft.com/zh-cn/sql/reportin ...

  8. [ARC096C] Everything on It 补题记录

    题目链接 题目大意: 对于集合 \(\{1,2,\dots,n\}\) ,求它的子集族中,有多少个满足: 任意两个子集互不相同: \(1,2,\dots,n\) 都在其中至少出现了 \(2\) 次. ...

  9. Servlet-2获取请求,响应结果

    获取请求参数值1)HttpServletRequest ①      该接口是ServletRequest接口的子接口,封装了HTTP请求的相关信息,由Servlet容器创建其实现类对象并传入serv ...

  10. SpringBoot快速整合通用Mapper

    前言 后端业务开发,每个表都要用到单表的增删改查等通用方法,而配置了通用Mapper可以极大的方便使用Mybatis单表的增删改查操作. 通用mapper配置 1.添加maven: <depen ...