传送门

题目大意:

小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的更多相关文章

  1. Codeforces 208E - Blood Cousins(树上启发式合并)

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

  2. CF 208E - Blood Cousins dfs序+倍增

    208E - Blood Cousins 题目:给出一棵树,问与节点v的第k个祖先相同的节点数有多少个. 分析: 寻找节点v的第k个祖先,这不就是qtree2简化版吗,但是怎么统计该祖先拥有多少个深度 ...

  3. Codeforces 246E - Blood Cousins Return (树上启发式合并)

    246E - Blood Cousins Return 题意 给出一棵家谱树,定义从 u 点向上走 k 步到达的节点为 u 的 k-ancestor,每个节点有名字,名字不唯一.多次查询,给出 u k ...

  4. Codeforces 246E Blood Cousins Return(树上启发式合并)

    题目链接 Blood Cousins Return #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) f ...

  5. CF 208E. Blood Cousins [dsu on tree 倍增]

    题意:给出一个森林,求和一个点有相同k级祖先的点有多少 倍增求父亲然后和上题一样还不用哈希了... #include <iostream> #include <cstdio> ...

  6. [cf contest246] E - Blood Cousins Return

    [cf contest246] E - Blood Cousins Return time limit per test 3 seconds memory limit per test 256 meg ...

  7. CF208E Blood Cousins

    Blood Cousins 题目描述 小C喜欢研究族谱,这一天小C拿到了一整张族谱. 小C先要定义一下k-祖先. x的1-祖先指的是x的父亲 x的k-祖先指的是x的(k-1)-祖先的父亲 小C接下来要 ...

  8. CF 246E. Blood Cousins Return [dsu on tree STL]

    题意: 一个森林,求k级后代中多少种不同的权值 用set维护每个深度出现的权值 一开始一直在想删除怎么办,后来发现因为当前全局维护的东西里都是当前子树里的,如果要删除那么当前一定是轻儿子,直接清空se ...

  9. codeforces246E Blood Cousins Return

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

随机推荐

  1. PyCharm使用技巧总结

    PyCharm高频使用快捷键 快速修复:ALT + ENTER 搜索: 双击Shif 垂直分隔窗口: ALT + V 另起一行: SHIFT + ENTER 删除当前插入符所在的行: Ctrl + Y ...

  2. 命令行界面CLI

    1.hive   -e --执行一个或多个查询 hive -e "select * from student limit 3" 2. hive -e     > 将临时查询保 ...

  3. LeetCode--055--跳跃游戏(java)

    给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示例 1: 输入: [2,3,1,1,4] 输出: true ...

  4. basic deepwalk

    Get to know How deepwalk works by this project. Two steps: 1. gen the graph, and gen the corpus on t ...

  5. 第六周作业—N42-虚怀若谷

    一.自建yum仓库,分别为网络源和本地源 [root@centos7 ~]# cd /etc/yum.repos.d/ [root@centos7 yum.repos.d]# mkdir bak #建 ...

  6. Python 爬虫实战(1):分析豆瓣中最新电影的影评

    目标总览 主要做了三件事: 抓取网页数据 清理数据 用词云进行展示 使用的python版本是3.6 一.抓取网页数据 第一步要对网页进行访问,python中使用的是urllib库.代码如下: from ...

  7. php中ajax的使用实例讲解

    一.总结 1.多复习:代码都挺简单的,就是需要复习,要多看 2.ajax原理:ajax就是部分更新页面,其实还在的html页面监听到事件后,然后传给服务器进行操作,这里用的是get方式来传值到服务器, ...

  8. [CF959A]Mahmoud and Ehab and the even-odd game题解

    题意简述 一个数n,Mahmoud珂以取(即如果取\(k\),使\(n = n - k\))一个正偶数,Ehab珂以取一个正奇数,一个人如果不能取了(对于Mahmoud和Ehab \(n = 0\), ...

  9. JS占位符替换

    String.prototype.format = function() { if(arguments.length === 0) return this; var obj = arguments[0 ...

  10. LLDB动态调试