2014 csu校赛 I 题,比赛的时候拿着他看了几个小时愣是没弄出好的方法,我们也想过统计出每个root的节点总数,然后减去离它d层的子节点的数目,即为答案。但是因为树的存储是无序的,所以每次为了找到子节点还是需要搜索,这肯定是承受不了的。

事实上,这个思路大体是对的,只是需要进行预处理,使得在找离它为d层的子节点能尽量节约时间,此外,如果找到了子节点挨个去减,也是很费时的,因为这些子节点必定处在同一层,他们的bfs序是连续的,故比较容易想到用前缀和来快速求得某一层的所有儿子的数目。

我们看这样的树

因此我们如果能把每个root的dfs时间戳的最小值和最大值给记录一下,再求出bfs序,则,对于某一层的所有节点,只要是时间戳在该root的最小值和最大值范围内,则必定是我们要求得孩子节点。

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define N 100010
using namespace std;
vector <int> deep_num[N];
int u[N],v[N],nt[N],ft[N],cnt,dfs_clock;
int last[N][],max_deep[N],tot[N],deep[N],sum[N];
void add(int a,int b){
u[cnt]=a;
v[cnt]=b;
nt[cnt]=ft[a];
ft[a]=cnt++;
}
void init(int num)
{
cnt=;
dfs_clock=;
sum[]=; for (int i=;i<=num;i++){
ft[i]=-;
nt[i]=;
u[i]=v[i]=;
deep_num[i].clear();
deep_num[i].push_back(); //先给每个层预先加一个0,方便之后处理
}
}
void dfs(int u,int d)
{
last[u][]=++dfs_clock;
deep_num[d].push_back(u);//这里直接把节点存入相应的层,省去了BFS,直接达到了计算BFS序的作用
tot[u]=;
deep[u]=d;
max_deep[u]=d;
for (int w=ft[u];w>=;w=nt[w]){
int x=v[w];
dfs(x,d+);
tot[u]+=tot[x];//计算root节点下的节点总数
max_deep[u]=max(max_deep[u],max_deep[x]);//记录该root最大层有多深
}
last[u][]=dfs_clock;
if (deep_num[deep[u]].size()>)
sum[u]=sum[deep_num[deep[u]][deep_num[deep[u]].size()-]]+tot[u];//因为没有进行BFS,所以计算前缀和要稍微麻烦一点,根据存贮好的每一层的节点来计算
else
sum[u]=sum[deep_num[deep[u]-][deep_num[deep[u]-].size()-]]+tot[u];
}
int query(int x,int d)
{
if (max_deep[x]<=deep[x]+d-)//如果该root没有那一层的孩子,则可以直接返回,因为肯定不需要减孩子了
return tot[x];
int val=last[x][];
int ret=tot[x];
int nd=deep[x]+d;
int L=,R=deep_num[nd].size()-,mid;
int a,b;
while (L<R)//
{ mid=(L+R)/;
//cout<<L<<" "<<R<<" "<<mid<<endl;
int nx=deep_num[nd][mid];
if (last[nx][]>=val) R=mid;
else L=mid+;
//cout<<nx<<" !!! "<<endl;
}
//cout<<"pass"<<endl;
a=deep_num[nd][L-];算出左边界,因为要算前缀和,所以L-1,这样前面的push 0在这里也起到作用了
val=last[x][];
L=,R=deep_num[nd].size()-;
while (L<R)
{
mid=R-(R-L)/;
int nx=deep_num[nd][mid];
if (last[nx][]<=val) L=mid;
else R=mid-;
// cout<<nx<<" ~~ "<<endl;
}
b=deep_num[nd][R];
//cout<<a<<" ab "<<b<<endl;
//cout<<sum[a]<<" sum "<<sum[b]<<endl;
ret-=sum[b]-sum[a]; //减去前缀和,其实还有个细节就是因为刚刚已经判断了,所以一定有孩子在这一层,所以这样减一定是合理的,不会出现没孩子也减掉的情况
return ret; }
int main()
{
int t,n,m,x,d;
scanf("%d",&t);
while (t--){
scanf("%d",&n);
init(n);
for (int i=;i<=n;i++){
int tmp;
scanf("%d",&tmp);
add(tmp,i);
}
dfs(,);
scanf("%d",&m);
while (m--){
scanf("%d%d",&x,&d);
int ans=query(x,d);
printf("%d\n",ans);
}
}
return ;
}

CSU_1414 Query On a Tree BFS序+DFS时间戳进行预处理的更多相关文章

  1. HDU 5274 Dylans loves tree(LCA+dfs时间戳+成段更新 OR 树链剖分+单点更新)

    Problem Description Dylans is given a tree with N nodes. All nodes have a value A[i].Nodes on tree i ...

  2. HDU 6191 Query on A Tree(可持久化Trie+DFS序)

    Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Othe ...

  3. 【BZOJ1803】Spoj1487 Query on a tree III 主席树+DFS序

    [BZOJ1803]Spoj1487 Query on a tree III Description You are given a node-labeled rooted tree with n n ...

  4. S - Query on a tree HDU - 3804 线段树+dfs序

    S - Query on a tree HDU - 3804   离散化+权值线段树 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度. 这个题目和之前写的那个给你一棵 ...

  5. BZOJ_1803_Spoj1487 Query on a tree III_主席树+dfs序

    BZOJ_1803_Spoj1487 Query on a tree III_主席树 Description You are given a node-labeled rooted tree with ...

  6. cf276E 两棵线段树分别维护dfs序和bfs序,好题回头再做

    搞了一晚上,错了,以后回头再来看 /* 对于每次更新,先处理其儿子方向,再处理其父亲方向 处理父亲方向时无法达到根,那么直接更新 如果能达到根,那么到兄弟链中去更新,使用bfs序 最后,查询结点v的结 ...

  7. UVA10410-Tree Reconstruction(BFS序和DFS序的性质)

    Problem UVA10410-Tree Reconstruction Accept:708  Submit:4330 Time Limit: 3000 mSec Problem Descripti ...

  8. HDU5957 Query on a graph(拓扑找环,BFS序,线段树更新,分类讨论)

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5957 题意:D(u,v)是节点u和节点v之间的距离,S(u,v)是一系列满足D(u,x)<=k的点 ...

  9. UVA10410 TreeReconstruction 树重建 (dfs,bfs序的一些性质,以及用栈处理递归 )

    题意,给你一颗树的bfs序和dfs序,结点编号小的优先历遍,问你可能的一种树形: 输出每个结点的子结点. 注意到以下事实: (1)dfs序中一个结点的子树结点一定是连续的. (2)bfs,dfs序中的 ...

随机推荐

  1. 008、Java中变量与常量的区别

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  2. ZOJ 3802 Easy 2048 Again 状态DP

    zoj 上次的月赛题,相当牛的题目啊,根本想不到是状态压缩好吧 有个预先要知道的,即500个16相加那也是不会超过8192,即,合并最多合并到4096,只有2的12次方 所以用状态压缩表示前面有的序列 ...

  3. python 文件夹递归

    import ospath = "F:/new" #文件夹目录datas = []def eachFile(filepath): fileNames = os.listdir(fi ...

  4. UVA - 1626 Brackets sequence (区间dp)

    题意:给定一个串,可能空串,或由'[',']','(',')'组成.问使其平衡所需添加最少的字符数,并打印平衡后的串. 分析:dp[i][j]表示区间(i,j)最少需添加的字符数. 1.递推. #in ...

  5. C++ Socket WSAENOBUFS WSAoverlapped

    WSARecv的时候,投递的接收缓冲区的大小设置为0. 然后手动调用非阻塞recv从缓冲区接受数据,直到WSAEWOULDBLOCK,不然会有很多的buffer被锁住,当客户端的数量达到一定数目时,就 ...

  6. mapper语句的一些问题,union连表查询和mapper中根据条件不同采用不同语句的查询问题

    根据业务要求,不同表查出来的内容天需要一起展示出来,并且还有分页之类的,不同表查询字段也不完全相同,这样就有一个问题,不同表如何接合在一起,不同字段怎么办? 这个问题就需要用到union联合查询,并将 ...

  7. nodejs学习笔记(一):centos7安装node环境

    由于windows环境安装nodejs只需要访问官方网站下载压缩包,解压即可. 首先检查自己是否安装==wget==,已安装可以跳过这步,未安装则需要先安装: linux yum install -y ...

  8. 用25行JavaScript语句实现一个简单的编译器

    原文:https://www.iteye.com/news/32680 译者注:即使对于专业程序员来说,构造一个编译器也是颇具挑战性的任务,本文将会引导你抽丝剥茧,一探究竟! 我已经写了几篇与编程语言 ...

  9. 九十四、SAP中ALV事件之八,显示功能按钮栏

    一.我们把其他代码都注释掉,直接写一行调用 SET PF-STATUS 'TIANPAN_TOOLS'. 二.运行程序,会看到我们上一篇所添加的相关功能栏图标, 三.点击不同图标,会按程序代码,有不同 ...

  10. 代做Assignment时排比结构的使用解析

    排比句式的作用想必各位留学生都不陌生,同理,在英文写作中,不管是从形式还是内容上来说,排比结构的作用都是强调.但是要注意,不能在分析的时候用太多这种套话,尽量还是能够根据具体情况具体分析.静态,小编将 ...