[Hdu3887]Counting Offspring

[Hdu3887]Counting Offspring
You are given a tree, it’s root is p, and the node is numbered from 1 to n.
Now define f(i) as the number of nodes whose number is less than i in all the succeeding nodes of node i.
Now we need to calculate f(i) for any possible i.
Input

Multiple cases (no more than 10), for each case:
The first line contains two integers n (0<n<=10^5) and p, representing this tree has n nodes, its root is p.
Following n-1 lines, each line has two integers, representing an edge in this tree.
The input terminates with two zeros.
给你一个树,问你对于每个节点,它的子树上标号比它小的点有多少个
N<=100000
Output

For each test case, output n integer in one line representing f(1), f(2) … f(n), separated by a space.
Sample Input

15 7
7 10
7 1
7 9
7 3
7 4
10 14
14 2
14 13
9 11
9 6
6 5
6 8
3 15
3 12
0 0
Sample Output

0 0 0 0 0 1 6 0 3 1 0 0 0 2 0

Sol:跑出dfs序来,然后树状数组查询下就好了。此题还可以用线段树的合并来做。

参考:https://www.cnblogs.com/cutemush/p/11835761.html

#include<cstdio>
#include<vector>
#include<cstring>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000+10;
vector<int>G[maxn];
int n,p,t;
int l[maxn],r[maxn],tree[maxn];
void dfs(int u,int fa)
//求出dfs序,某个树上所有结点必然是连在一起的 
{
    l[u]  = ++t; 
    int len = G[u].size();
    for(int i=0;i<len;i++)
    {
        int v = G[u][i];
        if(v==fa) continue;
        dfs(v,u);
    }
    r[u] = t; 
	
}
inline int lowbit(int i)
{
	return i&(-i); 
}
inline void add(int i,int d)
{
    while(i<=n)
    {
        tree[i] += d;
        i += lowbit(i);
    }
}
inline int getsum(int i)
{
    int ans = 0;
    while(i)
    {
        ans += tree[i];
        i -= lowbit(i);
    }
    return ans;
}
int main()
{
    int u,v;
    while(scanf("%d%d",&n,&p))//N个点,P为root点 
    {
        if(n==0&&p==0) break;
        memset(tree,0,sizeof(tree));
        for(int i=0;i<=n;i++) 
		    G[i].clear();
        for(int i=1;i<n;i++)
		{
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        t = 0; 
       dfs(p,-1);
      // for (int i=1;i<=n;i++)
       //cout<<i<<"  "<<l[i]<<"  "<<r[i]<<endl;
        for(int i=1;i<=n;i++)
		//统计对于i来说,有多少个点值比它小 
        {
            printf("%d",getsum(r[i])-getsum(l[i]-1));  
            //统计从[l(i),r(i)]这一段中有多少数字比i小 
            if(i==n) 
			   printf("
");
            else 
			    printf(" ");
            add(l[i],1);
        }
    }
    return 0;
}
/*
input 
4 4
4 3
4 2
3 1
结点编号 入   出 
1        3    3
2        4    4
3        2    3
4        1    4
output
0 0 1 3
*/

 

  

原文地址:https://www.cnblogs.com/cutemush/p/11794548.html