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序中的 ...
随机推荐
- excel 两列值匹配取另外一列值 INDEX MATCH 函数
=INDEX($D:$D,MATCH(K68,$C:$C,0))
- react 如何引入打印控件 CLodop
下载插件,官网地址 http://www.lodop.net/download.html ,选择综合版,解压下载的文件.直接点击 安装,很简单,就不一一说明了. 复制下面几个文件,到react项目中 ...
- 解决oracle 11g 导出空表的方法
ORACLE 11G中有个新特性,当表无数据时,不分配segment,以节省空间. 解决方法: 1)insert一行,再rollback就产生segment了 该方法是在在空表中插入数据,再删除,则产 ...
- java正则表达式校验密码必须是包含大小写字母、数字、特殊符号的8位以上组合
一.需求:密码必须是包含大写字母.小写字母.数字.特殊符号(不是字母,数字,下划线,汉字的字符)的8位以上组合 二.方案:利用正则表达式来校验 三.思路:排除法 1.排除大写字母.小写字母.数字.特殊 ...
- php观察者模式。
第一次写博客,大家多多关照!欢迎拍砖哦! 我也刚学设计模式,所以记录下来. <?php class person{ public $name; public $birthday; public ...
- nui UI 具有右键属性的菜单树
参考示例:树右键菜单 一:创建ContextMenu <ul id="treeMenu" class="nui-contex ...
- 吴裕雄--天生自然C++语言学习笔记:C++ 接口(抽象类)
接口描述了类的行为和功能,而不需要完成类的特定实现. C++ 接口是使用抽象类来实现的,抽象类与数据抽象互不混淆,数据抽象是一个把实现细节与相关的数据分离开的概念. 如果类中至少有一个函数被声明为纯虚 ...
- Mysql: if 结构
if结构 语法 if 条件1 then 语句1; elseif 条件2 then 语句2; ... else 语句n; # 可以不写 应用场合:应用在begin end 中 SEL ...
- python_re正则表达
re模块就本质而言,正则表达式(或RE)是一种小型的.高度专业化的编程语言,(在python中)它内嵌在Python中,并通过re模块实现,正则表达式模块被编译成一系列的字节码,然后由用C编写的匹配引 ...
- UVA - 10384 The Wall Pusher(推门游戏)(IDA*)
题意:从起点出发,可向东南西北4个方向走,如果前面没有墙则可走:如果前面只有一堵墙,则可将墙向前推一格,其余情况不可推动,且不能推动游戏区域边界上的墙.问走出迷宫的最少步数,输出任意一个移动序列. 分 ...