给你一棵树,每个节点都有个编号。
让你求一个节点他的子树中编号比他小的节点有几个。(编号唯一,从1-N,已给出根节点)
解:
树状数组统计。转化为线性序列。
可以想到的是,若要统计一个节点,那么比它小的孩子必须先插完,然后统计就行了。对于一个节点i来说,只要把所有x<i的都给插到L[x]里面,然后统计L[i]到R[i]有多少个1就行了。
那么对于所有节点来说也是这样的,从一开始插,插一个,查询一个即可。
完全是自己想的,代码也是自己写的,感觉自己的能力真的在一步一步增强。还自己手写了一个dfs。。。到底STACK OVERFLOW是不是dfs太深的缘故啊。好像是。因为我手写了一个栈就过了。
/*
Pro: 0
Sol:
date:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#define maxn 111111
using namespace std;
//linr ????
int n,p,head[maxn],esub,a,b,li,L[maxn],R[maxn],ans[maxn],c[maxn];
struct Edge{
int v,nxt;
}edge[maxn << 1];
void add(int u, int v){
edge[esub].v = v;
edge[esub].nxt = head[u];
head[u] = esub ++;
}
void dfs(int rt){
bool vis[maxn];
memset(vis,0,sizeof(vis));
stack <int> ss; bool flag ;
vis[rt] = true; ss.push(rt); L[rt] = ++ li;
while(!ss.empty()){
int tmp = ss.top();
flag = true;
for(int j = head[tmp]; j != -1; j = edge[j].nxt){
if(!vis[edge[j].v]){
ss.push(edge[j].v);
L[edge[j].v] = ++ li;
vis[edge[j].v] = true;
flag = false;
break;
}
}
if(flag) {R[tmp] = li; ss.pop();}
}
}
//void dfs(int rt){
// L[rt] = ++li;
// for(int j = head[rt]; j != -1 ; j = edge[j].nxt){
// if(!L[edge[j].v]) dfs(edge[j].v);
// }
// R[rt] = li;
//}
void modify(int pos, int val){
while(pos <= n){
c[pos] += val;
pos += (pos & -pos);
}
}
int getsum(int pos){
int sum = 0;
while(pos){
sum += c[pos];
pos -= (pos & -pos);
}return sum;
}
bool cmpx(int a,int b) {return L[a] < L[b];}
int main(){
while(~scanf("%d%d",&n,&p) && (n || p)){
if(n == 1)
{puts("0"); continue;}
memset(head,-1 ,sizeof(head));
memset(c,0,sizeof(c));
memset(L,0,sizeof(L));
esub = li = 0;
for(int i = 0; i < n - 1; i ++){
scanf("%d%d",&a,&b);
add(a,b); add(b,a);
}
dfs(p);
//很容易想到的是先插小的,并且是离线处理。
for(int ii = 1; ii <= n; ii ++){
ans[ii] = getsum(R[ii]) - getsum(L[ii] - 1);
modify(L[ii],1);
}
for(int ii = 1; ii < n; ii ++)
printf("%d ",ans[ii]);
printf("%d\n",ans[n]);
}
return 0;
}