【CF375D】Trees and Queries——树上启发式合并
(题面不是来自Luogu)
题目描述
有一个大小为n且以1为根的树,树上每个点都有对应的颜色ci。现给出m次询问v, k,问以v为根的子树中有多少种颜色至少出现了k次。
输入格式
第一行两个数n,m表示树的大小以及询问的次数。
第二行n个数表示树上每个结点的颜色。
接下来的n-1行,每行两个数a, b表示树上的边。
接下来m行,每行两个数v, k表示询问。
输出格式
m行,每行一个数表示第i次询问的答案。
样例输入1
8 5
1 2 2 3 3 2 3 3
1 2
1 5
2 3
2 4
5 6
5 7
5 8
1 2
1 3
1 4
2 3
5 3
样例输出1
2
2
1
0
1
样例输入2
4 1
1 2 3 4
1 2
2 3
3 4
1 1
样例输出2
4
数据范围
2≤n≤100000
1≤m≤100000
1≤ci≤100000
1≤a, b≤n, a≠b
1≤v≤n, 1≤k≤100000
对于其中30%的数据保证n,m≤100且ci≤n
对于其中60%的数据保证n≤5000
(7:20)今天为了打这个题的正解学了dsu on tree。需要学习的同学请看我的上一篇博客。
树上启发式合并主要解决的就是这类静态子树统计问题。
对于这题,我们维护两个数组cnt和upr,分别表示某种颜色出现的数量和出现次数大于某个次数的颜色的种类数。每次暴力累计子树信息时,出现一个颜色先++cnt[color[i]],然后++upr[color[i]]。容易想到,这样可以保证不重不漏地统计到所有达到upr[i]的颜色,并且不会重复累加。剩下的套dsu on tree板子即可。
代码:
- #include <cstdio>
- #include <iostream>
- #include <cctype>
- #include <cstring>
- #include <vector>
- #define maxn 100010
- using namespace std;
- template <class T>
- void read(T &x) {
- x = 0;
- char ch = getchar();
- while (!isdigit(ch))
- ch = getchar();
- while (isdigit(ch)) {
- x = x * 10 + (ch ^ 48);
- ch = getchar();
- }
- }
- int n, m, color[maxn], upr[maxn], cnt[maxn], ans[maxn];
- struct Query {
- int k, id;
- };
- vector<Query> Q[maxn];
- int head[maxn], top;
- struct E {
- int to, nxt;
- } edge[maxn << 1];
- inline void insert(int u, int v) {
- edge[++top] = (E) {v, head[u]};
- head[u] = top;
- }
- int size[maxn], son[maxn];
- void dfs(int u, int pre) {
- size[u] = 1;
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == pre) continue;
- dfs(v, u);
- size[u] += size[v];
- if (size[son[u]] < size[v])
- son[u] = v;
- }
- }
- int CurSon;
- void cal(int u, int pre, int val) {
- if (val == -1)
- --upr[cnt[color[u]]];
- cnt[color[u]] += val;
- if (val == 1)
- ++upr[cnt[color[u]]];
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == CurSon || v == pre) continue;
- cal(v, u, val);
- }
- }
- void dsu(int u, int pre, bool op) {
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == pre || v == son[u]) continue;
- dsu(v, u, 0);
- }
- if (son[u])
- dsu(son[u], u, 1), CurSon = son[u];
- cal(u, pre, 1); CurSon = 0;
- for (int i = 0; i < Q[u].size(); ++i)
- ans[Q[u][i].id] = upr[Q[u][i].k];
- if (!op)
- cal(u, pre, -1);
- }
- int main() {
- // freopen("count.in", "r", stdin);
- // freopen("count.out", "w", stdout);
- read(n), read(m);
- for (int i = 1; i <= n; ++i)
- read(color[i]);
- int u, v;
- for (int i = 1; i < n; ++i) {
- read(u), read(v);
- insert(u, v), insert(v, u);
- }
- int k;
- for (int i = 1; i <= m; ++i) {
- read(v), read(k);
- Q[v].push_back((Query) {k, i});
- }
- dfs(1, 0);
- dsu(1, 0, 1);
- for (int i = 1; i <= m; ++i)
- printf("%d\n", ans[i]);
- return 0;
- }
转载于:https://www.cnblogs.com/TY02/p/11219304.html
【CF375D】Trees and Queries——树上启发式合并相关推荐
- 树上启发式合并问题 ---- D. Tree and Queries[树上启发式合并+树状数组]
题目链接 题目大意: 就是给你一棵树,树上每个节点都有一个颜色,在你mmm次询问每次询问给你一个节点uuu和一个数字kkk,问你在uuu这颗子树里面又少种颜色的结点个数是大于kkk; 解题思路: 看到 ...
- CodeForces - 375D Tree and Queries(树上启发式合并)
题目链接:点击查看 题目大意:给出一棵有根树,每个节点都有一个编号代表颜色,现在给出m个询问,每个询问的形式为u k,需要回答以u为根节点的子树中,数量超过k的颜色有多少种 题目分析:树上启发式合并模 ...
- 树上启发式合并问题 ---- 2019icpc南昌 K. Tree (树上启发式合并 + 动态开点线段树)
题目链接 题目大意: 就是给你一颗树,每个点有个权值viv_ivi,问你有多少对(x,y)(x,y)(x,y)满足: xxx不是yyy的祖先 yyy也不是xxx的祖先 xxx和yyy的距离不超过kk ...
- 树上启发式合并问题 ---- D. Tree Requests [状态压缩+树上启发式合并]
题目链接 题目大意: 就是给你一颗树,树上每个点都有一个小写字母,现在给你m∈[1,5e5]m\in [1,5e5]m∈[1,5e5]次询问,每次询问给你一个u,和deep,问你在u这课子树中,距离1 ...
- 树上启动式合并问题 ---- D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths [状态压缩+树上启发式合并]
题目链接 题目大意: 一棵根为1 的树,每条边上有一个字符(a−va−va−v共22种). 一条简单路径被称为Dokhtar−kosh当且仅当路径上的字符经过重新排序后可以变成一个回文串. 求每个子树 ...
- 2019 ICPC 南昌 K. Tree(树上启发式合并,平衡树 treap)
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 题目链接 https://nanti.jisuanke.com/t/42586 Problem 给定一 ...
- 【学习笔记】树上启发式合并
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 树上启发式合并 模板 复杂度分析 例题 **Problem A. Arpa's letter-m ...
- (树上启发式合并)CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://www.luogu.com.cn/problem/CF741D Pro ...
- 2020CCPC(长春) - Strange Memory(树上启发式合并+位运算)
题目大意:给出一棵 n 个点组成的有根树,一号节点是根节点,现在要求实现 n * n 的公式: 题目分析:树上启发式合并,需要修改部分内部实现,如果可以想到树启的话,那么应该往子树上去靠拢,当每个点作 ...
最新文章
- 由于使用zen coding导致myeclipse6.5中使用Alt+/不自动提示的解决办法
- 白话Elasticsearch01- 结构化搜索之使用term query来搜索数据
- Freemarker使用
- c语言两种加法,两个超长正整数的加法
- 深入理解操作系统内核架构(送书)!
- php判断中英文请求,并实现跳转
- 【转】 详解C中volatile关键字
- Android卡片设置透明度失效问题
- fortran95 文件读写等操作的字段参数总结
- SpringBoot验证码
- 什么叫工作波长,截止波长和波导波长
- (转)中小IT企业项目团队人员配置管理
- CVPR2019目标检测
- Domino RESTful
- Storm体系结构和概念解释
- JavaScript动态显示鼠标移动轨迹
- adb cat delay 2 second
- Ubuntu 搜狗输入法显示繁体,一直不显示简体
- tag标签是什么?对seo有什么用?
- BUUCTF:黑客帝国
热门文章
- 人工智能与电气工程及其自动技术论述
- 第四轮全国学科评估中获评A+的高校及学科(A+高校排行榜)
- 用上微软Bosque 困扰程序员30年的问题解决了
- json数据映射到html,在GoLang中将Json数据映射到Html模板
- java 实体属性个数_?Java中比较实用实体转换工具介绍
- 微型计算机的外存储器可与 直接打交道,微型计算机的外存储器可与( )直接打交道。...
- mysql 5.6 主从同步配置_Mysql 5.6主从同步配置
- linux运维必学python吗_linux运维一定要学python吗?
- 实用计算机技术选修,实用计算机组装与维护选修课学习心得
- java.lang中String类源码分析