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;
}
/*
问你对于每个节点,它的子树上标号比它小的点有多少个
*/

浙公网安备 33010602011771号