CSU 1414: Query on a Tree

预处理每个结点的子结点的个数sons , 则对x的询问可由sons[x]- sigma( sons[v] ) (v是到x距离为d的点)得到

怎么快速的找到这些v呢? 注意到距离x为d的点肯定在树的同一层....

可以对树进行dfs时记录每个结点时间戳的同时把每一层的结点保存下来,然后对每一层维护一个前缀和 如果v是x下面子结点那么v的时间戳肯定在x的范围内,这样就可以二分確定出前缀和的范围了.....

1414: Query on a Tree
Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 78  Solved: 23
[Submit][Status][Web Board]
Description
You are given a rooted tree with N nodes indexed by 1, 2, ..., N, and the root is indexed by 1. We will ask you to perform some queries of the following form:
x d : Ask for how many nodes there are in the subtree rooted at x, such that the distance between it and x is less than d.
Assume the length of each edge is 1.
Input
The first line contains an integer T (T > 0), giving the number of test cases.
For each test case, the first line contains an integer N (2 ≤ N ≤ 105). The next line contains N - 1 integers f2, f3, ..., fN (1 ≤ f2, f3, ..., fn ≤ N), where fi (2 ≤ i ≤ N) denotes the father of i is fi. Then follows a line with an integer M (1 ≤ M ≤ 105) giving the number of queries. Then follow M lines with two integers x, d (1 ≤ x, d ≤ N), giving the M queries.
Output
For each query, output how many nodes there are in the subtree rooted at x, such that the distance between it and x is less than d.
Sample Input

更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/

1
9
1 2 2 4 4 2 1 8
6
1 1
1 2
1 3
2 3
2 4
3 2

Sample Output

1
3
7
6
6
1

HINT

Source

中南大学第八届大学生程序设计竞赛
[Submit][Status][WebBoard]

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>  

using namespace std;  

const int maxn=110000;  

struct Edge
{
    int to,next;
}edge[maxn];
int Adj[maxn],Size;
vector<int> eg[maxn];
vector<int> pre_sum[maxn];
int dfn[maxn][2],sons[maxn],max_deep[maxn],Deep[maxn],id[maxn],ti,maxdeep,n;  

void init(int n)
{
    Size=0;
    memset(Adj,-1,sizeof(Adj));
    memset(dfn,0,sizeof(dfn));
    memset(sons,0,sizeof(sons));
    memset(Deep,0,sizeof(Deep));
    memset(id,0,sizeof(id));
    memset(max_deep,0,sizeof(max_deep));
    ti=0;maxdeep=0;
    for(int i=0;i<=n+20;i++)
    {
        pre_sum[i].clear(),pre_sum[i].push_back(0);
        eg[i].clear(),eg[i].push_back(0);
    }
}  

void Add_Edge(int u,int v)
{
    edge[Size].to=v;
    edge[Size].next=Adj[u];
    Adj[u]=Size++;
}  

void DFS(int u,int deep)
{
    dfn[u][0]=++ti;
    maxdeep=max(maxdeep,deep);
    eg[deep].push_back(u);
    int maxd=0;
    for(int i=Adj[u];~i;i=edge[i].next)
    {
        int v=edge[i].to;
        DFS(v,deep+1);
        maxd=max(maxd,max_deep[v]);
    }
    max_deep[u]=maxd+1;
    Deep[u]=deep;
    dfn[u][1]=ti;
    sons[u]=dfn[u][1]-dfn[u][0]+1;
}  

void prefix_sum()
{
    for(int i=1;i<=maxdeep;i++)
    {
        for(int j=1,sz=eg[i].size();j<sz;j++)
        {
            id[eg[i][j]]=j;
            pre_sum[i].push_back( pre_sum[i][j-1]+sons[eg[i][j]] );
        }
    }
}  

void Debug()
{
    for(int i=1;i<=n;i++)
    {
        cout<<i<<" st: "<<dfn[i][0]<<" et: "<<dfn[i][1]<<"   sons: "<<sons[i]<<endl;
    }
    cout<<"maxdeep: "<<maxdeep<<endl;
    for(int i=1;i<=maxdeep;i++)
    {
        cout<<i<<": "<<endl;
        for(int j=0,sz=eg[i].size();j<sz;j++)
        {
            cout<<eg[i][j]<<",";
        }
        cout<<endl;
    }
    cout<<"id: \n";
    for(int i=1;i<=maxdeep;i++)
    {
        cout<<i<<": "<<endl;
        for(int j=0,sz=eg[i].size();j<sz;j++)
        {
            cout<<id[eg[i][j]]<<",";
        }
        cout<<endl;
    }
    cout<<"prefix_sum: \n";
    for(int i=1;i<=maxdeep;i++)
    {
        cout<<i<<": "<<endl;
        for(int j=0,sz=eg[i].size();j<sz;j++)
        {
            cout<<pre_sum[i][j]<<",";
        }
        cout<<endl;
    }
    cout<<"max_deep: ";
    for(int i=1;i<=n;i++)
    {
        cout<<i<<" : "<<max_deep[i]<<endl;
    }
}  

void solve(int x,int d)
{
    int nowd=Deep[x];
    if(d>=max_deep[x])
    {
        printf("%d\n",sons[x]);
        return ;
    }
    int qd=nowd+d;
    ///二分左右区间
    int L=0,R=0,sz=eg[qd].size();
    int low,mid,high;
    ///....get left pos
    low=0,high=sz-1;
    while(low<=high)
    {
        mid=(low+high)/2;
        int ps=eg[qd][mid];
        if(dfn[ps][0]>=dfn[x][0])
        {
            L=eg[qd][mid-1]; high=mid-1;
        }
        else low=mid+1;
    }
    ///...get right pos
    low=0,high=sz-1;
    while(low<=high)
    {
        mid=(low+high)/2;
        int ps=eg[qd][mid];
        if(dfn[ps][1]<=dfn[x][1])
        {
            R=ps; low=mid+1;
        }
        else high=mid-1;
    }
    printf("%d\n",sons[x]-pre_sum[qd][id[R]]+pre_sum[qd][id[L]]);
}  

int main()
{
    int T_T;
    scanf("%d",&T_T);
    while(T_T--)
    {
        scanf("%d",&n);
        init(n+1);
        for(int i=2;i<=n;i++)
        {
            int fa;
            scanf("%d",&fa);
            Add_Edge(fa,i);
        }
        DFS(1,1);
        prefix_sum();
       // Debug();
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int x,d;
            scanf("%d%d",&x,&d);
            solve(x,d);
        }
    }
    return 0;
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索int
, include
, sizeof
, 结点
, memset
, The
V1.3.2
query on a tree、in a tree on a tree、count on a tree、on a tree、count on a tree ii,以便于您获取更多的相关知识。

时间: 2024-12-03 04:34:21

CSU 1414: Query on a Tree的相关文章

LINQ那些事儿(4)- Query Expression和Query Operator

我学习LINQ的时候是直接看MSDN和LINQ team的blog,经常会被里面的一些名词弄混,下面这些名词你都弄懂了吗? Expression Tree Expression Lambda Expression Query Expression Query Operator Expression Tree 和 Expression的区别类似XmlNode和XmlElement的区别.Expression Tree用于表达对IQueryable<T>类型数据源的查询树,是Select/Wher

如何使用XQI?

作为通讯媒体,XQI(Extensible Query Interface)是一种允许使用XML远程查询和插入数据库的服务.    XQI允许远程查询和插入使用搜索引擎,但不需要CGI应用(数据可以通过其他应用传递). 例子一:查询"Apple" 在 "Tree" <?xml version="1.0"?><GOXML><QUERY>  <KEYWORD>apple</KEYWORD> 

理解C# 3.0新特性之Extension方法浅议

在C#3.0中,引入了一些列新的特性,比如: Implicitly typed local variable, Extension method,Lambda expression, Object initializer, Anonymous type, Implicitly typed array, Query expression, Expression tree.个人觉得在这一系列新特性的,最具创新意义的还是Extension method, 它从根本上解决了这样的问题:在保持现有Type

深入理解C# 3.x的新特性(2):Extension Method[上篇]

在C#3.0中,引入了一些列新的特性,比如: Implicitly typed local variable, Extension method,Lambda expression, Object initializer, Anonymous type, Implicitly typed array, Query expression, Expression tree. 个人觉得在这一系列新特性的,最具创新意义的还是Extension method,它从根本上解决了这样的问题:在保持现有Type

PostgreSQL GUC 参数级别介绍

标签 PostgreSQL , 参数 , 参数级别 背景 在添加GUC参数时,需要注意你添加的参数属于什么类别的参数. 例如如果你想让普通用户能随时修改它,那么你需要将参数级别设置为PGC_USERSET.如果你想让超级用户能在线修改它,那么你需要将它设置为PGC_SUSET.如果你想让它能够在修改配置参数并通过信号生效,那么需要设置为PGC_SIGHUP. GUC参数相关的代码如下 src/backend/utils/misc/guc.c 参数级别介绍 /* * Displayable nam

用javascript实现兼容IE7的类库 IE7_0_9.zip提供下载_javascript技巧

IE7 loads and parses all style sheets into a form that Explorer can understand. You can then use most CSS2/CSS3 selectors without having to resort to CSS hacks. The lightweight script is a single-line inclusion in your HTML/XML document. No alteratio

UVa 112 Tree Summing (scanf()去空格&amp;amp;递归&amp;amp;二叉树遍历)

112 - Tree Summing Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=48 Background LISP was one of the earliest high-level programming languages and, with FORTRAN, is one o

线段树(Segment Tree)

1.概述 线段树,也叫区间树,是一个完全二叉树,它在各个节点保存一条线段(即"子数组"),因而常用于解决数列维护问题,基本能保证每个操作的复杂度为O(lgN). 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点. 对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度. 使用线段树可以

关于DIMMQ: Discardable In-Memory Materialized Query

背景 最近在看CBO在不同系统里的实现方式,比如flink里在编译时对plan的CBO优化,以及运行时的CBO:Hive.Apache Calcite(即Optiq)的一些内容. 今天第一次看到DIMMQ的概念,聊聊我的几点看法. 参考文章:Discardable Memory and Materialized Queries: Put your memory into its right place in the storage hierarchy for efficient queries