博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces 208E - Blood Cousins(树上启发式合并)
阅读量:5922 次
发布时间:2019-06-19

本文共 2480 字,大约阅读时间需要 8 分钟。

题意

给出一棵家谱树,定义从 u 点向上走 k 步到达的节点为 u 的 k-ancestor。多次查询,给出 u k,问有多少个与 u 具有相同 k-ancestor 的节点。

分析

设 rt 为 u 的 k-ancestor。问题可以转换成在以 rt 为根的子树下,有多少个节点的深度与 u 相同。

预处理出离 u 距离为 k 的祖先 rt 。
我们可以把所有的查询用向量存起来(祖先节点,要查询的节点的深度,对应查询的id),在遍历到某个祖先节点时,统计那个子树下,我们所要查询的某个节点深度的数量,直接去更新答案。也就是说子树的状态信息(数量信息)可以复用,也就是说可以套用 树上启发式合并。

code

#include
using namespace std;typedef long long ll;const int MAXN = 1e5 + 10;int n;int fa[MAXN][20], son[MAXN], dep[MAXN], siz[MAXN];int col[MAXN];int cnt, head[MAXN];struct Edge { int to, next;} e[MAXN << 1];struct Ex { int x, c;};vector
ex[MAXN];void addedge(int u, int v) { e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++; e[cnt].to = u; e[cnt].next = head[v]; head[v] = cnt++;}void dfs(int u) { siz[u] = 1; son[u] = 0; for(int i = 1; i < 20; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for(int i = head[u]; ~i; i = e[i].next) { if(e[i].to != fa[u][0]) { fa[e[i].to][0] = u; dep[e[i].to] = dep[u] + 1; dfs(e[i].to); if(siz[e[i].to] > siz[son[u]]) son[u] = e[i].to; siz[u] += siz[e[i].to]; } }}int getAn(int u, int d) { for(int i = 0; i < 20; i++) { if(d >> i & 1) { u = fa[u][i]; } } return u;}int vis[MAXN], ans[MAXN], C[MAXN];void change(int u, int c) { C[dep[u]] += c; for(int i = head[u]; ~i; i = e[i].next) { if(e[i].to != fa[u][0] && !vis[e[i].to]) change(e[i].to, c); }}void dfs1(int u, int flg) { for(int i = head[u]; ~i; i = e[i].next) { if(e[i].to != fa[u][0] && e[i].to != son[u]) dfs1(e[i].to, 1); } if(son[u]) { dfs1(son[u], 0); vis[son[u]] = 1; } change(u, 1); int sz = ex[u].size(); for(int i = 0; i < sz; i++) { ans[ex[u][i].x] = C[ex[u][i].c]; } if(son[u]) vis[son[u]] = 0; if(flg) change(u, -1);}int main() { scanf("%d", &n); memset(head, -1, sizeof head); cnt = 0; for(int i = 1; i <= n; i++) { int x; scanf("%d", &x); addedge(i, x); } dfs(0); int m; scanf("%d", &m); for(int i = 0; i < m; i++) { int x, y; scanf("%d%d", &x, &y); if(dep[x] - y <= 0) { ans[i] = 1; continue; } int anc = getAn(x, y); ex[anc].push_back(Ex{i, dep[x]}); } dfs1(0, 0); for(int i = 0; i < m; i++) { printf("%d%c", ans[i] - 1, " \n"[i == m - 1]); } return 0;}

转载于:https://www.cnblogs.com/ftae/p/7203320.html

你可能感兴趣的文章
Python爬虫笔记3-解析库Xpath的使用
查看>>
猴子数据教你如何快速查询域名备案是否存在
查看>>
【跃迁之路】【735天】程序员高效学习方法论探索系列(实验阶段492-2019.2.25)...
查看>>
小程序红包雨
查看>>
开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
查看>>
第十二课时:渲染函数和JSX快速掌握
查看>>
Visio替代图表工具 - 为什么Visual Paradigm Online?
查看>>
市场变冷,不要灰心。更应该延长你的黄金岁月
查看>>
微服务之数据同步Porter
查看>>
从前端程序员的视角看小程序的稳定性保障
查看>>
Flutter 1.2 发布,添加应用内支付和 App Bundles
查看>>
docker笔记2-镜像与容器
查看>>
如何使用less实现随机下雪动画详解
查看>>
完成端口服务器模型
查看>>
python 图像处理:一福变五福
查看>>
el-dialog 模态框拖拽
查看>>
教你React Native使用fetch实现图片上传
查看>>
Linux php7.0安装phpredis
查看>>
彻底弄懂 JavaScript 执行机制
查看>>
另类爬虫:从PDF文件中爬取表格数据
查看>>