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. 047、Java中使用if…else if…else判断

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

  2. NPOI读取excel 空行

    if (sheet.GetRow(i) != null) 每行判断一下,避免出错.真是蛋疼.

  3. Win7安装Oracle Instantclient ODBC驱动 后配置DSN时出错的解决办法 SQORAS32

    安装过程简述 oracle官网下载了 instantclient-odbc-nt--.zip instantclient-basic-nt-.zip 我这是32位版的win7,按照需要下载对应的版本. ...

  4. WC2020 联训 #19 矩阵

    好不容易自己切一道题 链接 Description 在一个 \(n×(n+1)\) 的棋盘上放棋子, \(n\) 行中每行都恰好有两枚棋子,并且 \(n+1\) 列中每列都至多有两枚棋子,设 \(n= ...

  5. Percona-Toolkit 之 pt-kill 低效SQL

    [root@ tools]#vi ptkill_master.confuser=rootpassword=asd.123port=3306busy-time=5printkill /u01/soft/ ...

  6. python csv

    Python 读取csv的某行 Python 读取csv的某列 Python写了一个可以提取csv任一列的代码,欢迎使用.Github链接 两个list写入csv文件 column1,column2 ...

  7. 070-PHP数组相加

    <?php $arr1=array('a','b','c'); //定义一个数组 echo '数组$arr1的信息:<br />'; print_r($arr1); //输出数组信息 ...

  8. 12 文件流(Unity3D)

      关于文件操作在脚本中可以通过xml或其他的与文件相关的类中封装的一些方法可读取本地Asset文件夹下的xml文档和json文档到游戏中.但是这样操作文件难免会有拖延,C#提供了一种文件操作的方法, ...

  9. vant库在vue全局引入toast组件

    第一步: 在config中引入 // 全局引入vant的提示框 import { Toast } from "vant"; Vue.use(Toast); 第二步: 在组要的.vu ...

  10. 每天一点点之vue框架开发 - 部署到线上

    1.在项目根目录下运行如下命令 npm run build 会生成一个dist目录, 2.然后将dist目录上传至服务器就可以访问页面了,不需要配置vue环境了.