HDU3887:线段树+DFS序

Counting Offspring

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3907    Accepted Submission(s): 1322

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

Author

bnugong

Source

2011 Multi-University Training Contest 5 - Host by BNU

题解

先DFS序一遍,再建立线段树,初始化为0。接下来从1到n遍历,每次查询编号比它小的结点个数,再将这个数放入,线段树加1。代码如下

		for(int i=1;i<=n;i++){  //id[]数组记录DFS序后的新编号
			printf("%d%c",query(1,id[i],id[i]+sz[i]-1),i!=n?' ':'\n');
			updata(1,id[i]);   //id[i]+1
		}
#include <bits/stdc++.h>
using namespace std;
int const N = 100000 + 10;
int n,p,tot;
int first[N],ne[2*N],to[2*N],sz[N],id[N];
struct Node
{
	int l,r,sum;
}node[N<<2];
void add(int x,int y){
	ne[++tot] = first[x];
	to[tot] = y;
	first[x] = tot;
}
void DFS(int u,int fa){
	id[u] = ++tot;
	sz[u] = 1;
	for(int i=first[u];i;i=ne[i]){
		int v = to[i];
		if(v == fa) continue;
		DFS(v,u);
		sz[u] += sz[v];
	}
}
void push_up(int id){
	node[id].sum = node[id<<1].sum + node[id<<1|1].sum;
}
void build(int id,int l,int r){
	node[id].l = l,node[id].r = r;
	node[id].sum = 0;
	if(l == r)	return;
	else{
		int mid = (l + r) >> 1;
		build(id<<1,l,mid);
		build(id<<1|1,mid+1,r);
	}
}
int query(int id,int L,int R){
	int l = node[id].l,r = node[id].r;
	if(L <=l && r <= R)	return node[id].sum;
	else{
		int mid = (l + r) >> 1;
		int res = 0;
		if(L <= mid)	res += query(id<<1,L,R);
		if(mid < R)		res += query(id<<1|1,L,R);	
		return res; 
	}
}
void updata(int id,int pos){//pos值加1
	int l = node[id].l,r = node[id].r;
	if(l == r)	node[id].sum++;
	else{
		int mid = (l + r) >> 1;
		if(pos <= mid)	updata(id<<1,pos);
		else 			updata(id<<1|1,pos);
		push_up(id);
	}
}
int main(){
	while(~scanf("%d%d",&n,&p)){
		if(!n && !p)	break;
		tot = 0;
		memset(first,0,sizeof(first));
		for(int i=1;i<=n-1;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			add(x,y);	add(y,x);
		}
		tot = 0;
		DFS(p,0);
		build(1,1,n);
		for(int i=1;i<=n;i++){  //id[]数组记录DFS序后的新编号
			printf("%d%c",query(1,id[i],id[i]+sz[i]-1),i!=n?' ':'\n');
			updata(1,id[i]);   //id[i]+1
		}
	}
	return 0;
}
/*
问你对于每个节点,它的子树上标号比它小的点有多少个 
*/

 

posted @ 2019-02-06 14:51  月光下の魔术师  阅读(5)  评论(0)    收藏  举报