传送门

题目大意:

小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. 2018-8-10-win10-uwp-读写XML

    title author date CreateTime categories win10 uwp 读写XML lindexi 2018-08-10 19:16:51 +0800 2018-2-13 ...

  2. Python2视频教程

    目录 1. 说明 1.1. 马哥视频_修复v1 1.2. 马哥视频_修复v2 2. 目录 3. 下载链接 1. 说明 Python从入门到精通视频(全60集)马哥教育视频(已修复部分视频无声音的问题+ ...

  3. ubuntu16.04安装mysql数据库

    安装 sudo apt-get install mysql-server(安装过程中按提示设置root密码) sudo apt-get install mysql-client sudo apt-ge ...

  4. LightOJ 1289 LCM from 1 to n(位图标记+素数筛

    https://vjudge.net/contest/324284#problem/B 数学水题,其实就是想写下位图..和状压很像 题意:给n让求lcm(1,2,3,...,n),n<=1e8 ...

  5. hdu 4082 Hou Yi's secret(暴力枚举)

    Hou Yi's secret Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  6. ltp-ddt eth iperf

    ETH_S_PERF_IPERF_TCP_8K_1448B source 'common.sh'; run_iperf.sh -m -M 1500 -f M -d -t 60 -w 8K run_ip ...

  7. alert(1) to win 2

    function escape(s) { s = s.replace(/"/g, '\\"'); return '<script>console.log("' ...

  8. git log的个性化设置

    --date=(relative|local|default|iso|rfc|short|raw) Only takes effect for dates shown in human-readabl ...

  9. linux系统基础的优化以及常用命令

    编辑网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-eth0 修改配置参数 ONBOOT= yes启动或者关闭ipsystemctl restart/s ...

  10. 6,Stack

    一,Stack简介 Stack是栈.它的特性是:先进后出(FILO, First In Last Out). java工具包中的Stack是继承于Vector(矢量队列)的,由于Vector是通过数组 ...