Codeforces 208E. Blood Cousins
题目大意:
小C喜欢研究族谱,这一天小C拿到了一整张族谱。
小C先要定义一下k-祖先。
- x的1-祖先指的是x的父亲
- x的k-祖先指的是x的(k-1)-祖先的父亲
小C接下来要定义k-兄弟
- x的k-兄弟指的是与x的k-祖先相同的人
- 如果不存在k-祖先那么x没有k-兄弟
小C想问问你,x到底有多少k-兄弟?小C打算问Q次这样的问题。
数据范围:
$n<=10^5,Q<=10^5$
$dsu\ on\ tree$ 基础题,当然也有显然的在线做法
对于每个询问 $(x,k)$,不妨转换为 $(u,v)$ ,表示求 $u$ 的子树中,与 $v$ 深度相同的节点数
考虑怎么离线搞,直接 $dsu\ on\ tree$ 维护一个统计各个深度节点数的数组 $cnt$ 即可
每次 $dfs$ 时最后 $dfs$ 重儿子,从而保留重儿子的 $cnt$ ,这样与每个节点 $u$ 有关的询问只要暴力枚举轻儿子子树即可
复杂度就是启发式合并的 $nlog_n$
具体看代码,注意数据是森林
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<set>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=2e6+;
int fir[N],from[N<<],to[N<<],cntt;
inline void add(int a,int b) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; }
int f[N][],dep[N],son[N],sz[N];//f是倍增数组,dep是节点深度,son是重儿子,sz是子树大小
void dfs1(int x)//预处理上面四个数组
{
dep[x]=dep[f[x][]]+; sz[x]=; int mx=;
for(int i=;i<=;i++) f[x][i]=f[f[x][i-]][i-];
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(v==f[x][]) continue;
f[v][]=x; dfs1(v);
if(sz[v]>sz[son[x]]) son[x]=v;
sz[x]+=sz[v];
}
}
struct dat{
int x,y,id;
inline bool operator < (const dat &tmp) const {
return x<tmp.x;
}
}d[N];//存询问
int n,Q;
int cnt[N],ans[N],id[N],dfs_clock;//id是dfs序为i的节点编号
void dfs2(int x,bool flag)//flag判断是否保留cnt
{
id[++dfs_clock]=x; int L=dfs_clock;//轻儿子子树dfs序的左区间
if(!son[x]) { if(flag) cnt[dep[x]]++; return; }
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(v==f[x][]||v==son[x]) continue;
dfs2(v,);//走轻儿子
}
int R=dfs_clock,t=lower_bound(d+,d+Q+,(dat){x,,})-d;//R是轻儿子子树右区间,t是第一个u为x的询问的位置
dfs2(son[x],);//最后走重儿子并保留cnt
for(int i=L;i<=R;i++) cnt[ dep[id[i]] ] ++;//枚举轻儿子子树,更新cnt
for(int i=t;d[i].x==x;i++) { ans[d[i].id]=cnt[dep[d[i].y]]-; }//更新ans
if(!flag) for(int i=L;i<=dfs_clock;i++) cnt[ dep[id[i]] ]--;//清空cnt
}
int rt[N],tot;//注意是森林,要存每个数的根
int main()
{
n=read(); int a,b;
for(int i=;i<=n;i++)
{
a=read();
add(a,i);
if(!a) rt[++tot]=i;
}
for(int i=;i<=tot;i++) dfs1(rt[i]);
Q=read();
for(int i=;i<=Q;i++)
{
a=read(),b=read(); int t=a;
for(int j=;j>=;j--) if(b&(<<j)) t=f[t][j];
d[i].x=t,d[i].y=a,d[i].id=i;
}
sort(d+,d+Q+);
for(int i=;i<=tot;i++) dfs2(rt[i],);
for(int i=;i<=Q;i++) printf("%d ",ans[i]);
return ;
}
Codeforces 208E. Blood Cousins的更多相关文章
- Codeforces 208E - Blood Cousins(树上启发式合并)
208E - Blood Cousins 题意 给出一棵家谱树,定义从 u 点向上走 k 步到达的节点为 u 的 k-ancestor.多次查询,给出 u k,问有多少个与 u 具有相同 k-ance ...
- CF 208E - Blood Cousins dfs序+倍增
208E - Blood Cousins 题目:给出一棵树,问与节点v的第k个祖先相同的节点数有多少个. 分析: 寻找节点v的第k个祖先,这不就是qtree2简化版吗,但是怎么统计该祖先拥有多少个深度 ...
- Codeforces 246E - Blood Cousins Return (树上启发式合并)
246E - Blood Cousins Return 题意 给出一棵家谱树,定义从 u 点向上走 k 步到达的节点为 u 的 k-ancestor,每个节点有名字,名字不唯一.多次查询,给出 u k ...
- Codeforces 246E Blood Cousins Return(树上启发式合并)
题目链接 Blood Cousins Return #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) f ...
- CF 208E. Blood Cousins [dsu on tree 倍增]
题意:给出一个森林,求和一个点有相同k级祖先的点有多少 倍增求父亲然后和上题一样还不用哈希了... #include <iostream> #include <cstdio> ...
- [cf contest246] E - Blood Cousins Return
[cf contest246] E - Blood Cousins Return time limit per test 3 seconds memory limit per test 256 meg ...
- CF208E Blood Cousins
Blood Cousins 题目描述 小C喜欢研究族谱,这一天小C拿到了一整张族谱. 小C先要定义一下k-祖先. x的1-祖先指的是x的父亲 x的k-祖先指的是x的(k-1)-祖先的父亲 小C接下来要 ...
- CF 246E. Blood Cousins Return [dsu on tree STL]
题意: 一个森林,求k级后代中多少种不同的权值 用set维护每个深度出现的权值 一开始一直在想删除怎么办,后来发现因为当前全局维护的东西里都是当前子树里的,如果要删除那么当前一定是轻儿子,直接清空se ...
- codeforces246E Blood Cousins Return
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
随机推荐
- python面向对象--反射机制
class Black: feture="ugly" def __init__(self,name,addr): self.addr=addr self.name=name def ...
- 树——binary-tree-postorder-traversal(树的后序遍历)
问题: Given a binary tree, return the postorder traversal of its nodes' values. For example: Given bin ...
- ps:建立规则选区
在前面的内容中,我们初步接触了色彩调整工具中的“色相/饱和度”工具[CTRL U],现在我们可以很容易地改变图像的色相.将如下左图的色相改为-100,形成如下中图的效果.但是这样做有一个局限,那就是只 ...
- alert(1) to win 12
- alert(1) to win
一. function escape(s) { return '<script>console.log("'+s+'");</script>'; } 两种思 ...
- [python 学习] random
1.random() 生成一个随机浮点数 import random # x 属于 [0,1) x = random.random() print x 2.uniform() 生成制定范围内的随机浮点 ...
- php函数漏洞
1.ereg — 正则表达式匹配 此函数遇 %00 截断. <?php $a = $_GET['pwd']; var_dump(ereg ("^[0-9]+$", $a)); ...
- thinkphp 模板
一. 模板函数 教程https://www.kancloud.cn/manual/thinkphp5/125005 我们往往需要对模板输出变量使用函数,可以使用: {$data.name|md5} ...
- 记录一下LEETheme库主题切换的使用
LEETheme库的位置:https://github.com/lixiang1994/LEETheme 从https://github.com/gsdios的SDAutolayoutDemo 中的白 ...
- Access分页语句
一.双TOP法高效率的Access分页的SQL语句,语法格式: SELECT * FROM (SELECT TOP "&pagesize&" * FROM (SEL ...