CSU_1414 Query On a Tree BFS序+DFS时间戳进行预处理
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时间戳进行预处理的更多相关文章
- 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 ...
- 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 ...
- 【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 ...
- S - Query on a tree HDU - 3804 线段树+dfs序
S - Query on a tree HDU - 3804 离散化+权值线段树 题目大意:给你一棵树,让你求这棵树上询问的点到根节点直接最大小于等于val的长度. 这个题目和之前写的那个给你一棵 ...
- 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 ...
- cf276E 两棵线段树分别维护dfs序和bfs序,好题回头再做
搞了一晚上,错了,以后回头再来看 /* 对于每次更新,先处理其儿子方向,再处理其父亲方向 处理父亲方向时无法达到根,那么直接更新 如果能达到根,那么到兄弟链中去更新,使用bfs序 最后,查询结点v的结 ...
- UVA10410-Tree Reconstruction(BFS序和DFS序的性质)
Problem UVA10410-Tree Reconstruction Accept:708 Submit:4330 Time Limit: 3000 mSec Problem Descripti ...
- 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的点 ...
- UVA10410 TreeReconstruction 树重建 (dfs,bfs序的一些性质,以及用栈处理递归 )
题意,给你一颗树的bfs序和dfs序,结点编号小的优先历遍,问你可能的一种树形: 输出每个结点的子结点. 注意到以下事实: (1)dfs序中一个结点的子树结点一定是连续的. (2)bfs,dfs序中的 ...
随机推荐
- window 如何访问虚拟机的mapreduce(遇到的坑)
首先 先把你虚拟机和本机网络链接弄通 (详情看上一篇) 一些关于mapreduce 和hadoop的配置都在上一篇 安装eclipse 的hadoop Map/Reduce插件详情 看其他博客园.. ...
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-step-forward
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
- P1002 写出这个数(Basic Level)
转跳点:
- 一些linux基础命令
linux基本命令: mkdir -p a/b/c (-p 递归创建目录) tree a (a是文件名) :可以查看某个文件的文件结构(ps:a)创建一个.txt文件 touch 文件名.txt 批量 ...
- pop3&smtp
pop3&smtp pop3 Post Office Protocol - Version 3 pop3协议是离线邮件协议,是客户端取邮件用的. 默认监听在TCP:110端口. POP3会话有 ...
- Python MongoDB 创建数据库
章节 Python MySQL 入门 Python MySQL 创建数据库 Python MySQL 创建表 Python MySQL 插入表 Python MySQL Select Python M ...
- ELK 教程
自从ELK首次推出以来,下载量达到了数百万次,是世界上最流行的日志管理平台.相比之下,Splunk - 该领域的历史领先者 - 宣布的客户总数才15000人. 章节 ELK 介绍 ELK 安装Elas ...
- 日期月份是英文转成数字——oracle
update table01 set F_DATE = to_char(to_date(F_DATE, 'dd-month-yy', 'NLS_DATE_LANGUAGE=AMERICAN'), 'y ...
- python --- 对于需要关联的接口处理方法
1.unittest对于需要关联的请求,怎么处理(如购物接口,需要先登录) a)把登录请求写到测试用例类的setUP函数中,这样每次调用测试用例,都会先执行setUP函数 b)全局变量的形式声明. c ...
- UVA - 116 Unidirectional TSP (单向TSP)(dp---多段图的最短路)
题意:给一个m行n列(m<=10, n<=100)的整数矩阵,从第一列任何一个位置出发每次往右,右上或右下走一格,最终到达最后一列.要求经过的整数之和最小.第一行的上一行是最后一行,最后一 ...