Counting Offspring
Problem Description
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.
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
解题思路:
题意:给定一棵树,求每个节点的子树中有几个编号比他小的。
要求有多少个比他小的,首先想到的是树状数组,可以很好的解决这个问题,再一个就是怎么解决子树的问题。
看了网上很多题解都是一样的dfs标记,然后左右sum一减,其实完全可以不用这么麻烦啊。
既然是只有子树会对结果造成影响,那么在进入一个节点的时候,先记录下sum(x)的值,然后在子树搜索完之后,再求一遍sum(x)的值,两个减一下就是答案。
最后再把x也标记。
AC代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+10;
vector<int> nodes[N];
int ans[N],vis[N];
int bit[N],n;
int lowbit(int x)
{
return x&(-x);
}
void add(int i,int x)
{
while(i<=n)
{
bit[i]+=x;
i+=lowbit(i);
}
}
void sub(int i,int x)
{
while(i<=n)
{
bit[i]-=x;
i+=lowbit(i);
}
}
int sum(int i)
{
int res=0;
while(i>0)
{
res+=bit[i];
i-=lowbit(i);
}
return res;
}
void dfs(int x)
{
int sz = nodes[x].size();
int pre = sum(x);
vis[x] = 1;
for(int i = 0 ; i < sz ; i ++)
if(!vis[nodes[x][i]])
dfs(nodes[x][i]);
ans[x] = sum(x)-pre;
add(x,1);
}
signed main()
{
int m;
while(~scanf("%lld%lld",&n,&m) && n+m )
{
for(int i = 0 ; i <= n ; i ++)
nodes[i].clear();
for(int i = 0 ; i < n-1 ; i ++)
{
int a,b;
scanf("%lld%lld",&a,&b);
nodes[a].push_back(b);
nodes[b].push_back(a);
}
memset(bit,0,sizeof(bit));
memset(vis,0,sizeof(vis));
dfs(m);
for(int i = 1 ; i < n ; i ++)
printf("%lld ",ans[i]);
printf("%lld\n",ans[n]);
}
}