武当派一共有 nn 人,门派内 nn 人按照武功高低进行排名,武功最高的人排名第 11,次高的人排名第 22,… 武功最低的人排名第 nn。现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师父,每个人可能有多个徒弟。
我们知道,武当派人才辈出,连祖师爷的武功都只能排行到 pp。也就是说徒弟的武功是可能超过师父的,所谓的青出于蓝胜于蓝。
请你帮忙计算每个人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟….)中,有多少人的武功超过了他自己。
输入格式
输入第一行两个整数 n, p(1 \le n \le 100000, 1 \le p \le n)n,p(1≤n≤100000,1≤p≤n)。
接下来 n-1n−1 行,每行输入两个整数 u, v(1 \le u, v \le n)u,v(1≤u,v≤n),表示 uu 和 vv 之间存在师徒关系。
输出格式
输出一行 nn 个整数,第 ii 个整数表示武功排行为 ii 的人的子弟有多少人超过了他。
行末不要输出多余的空格。
样例输入
10 5
5 3
5 8
3 4
3 1
2 1
6 7
8 7
9 8
8 10
样例输出
0 0 2 0 4 0 1 2 0 0
dfs序列+归并树 (查询区间小于val的值有几个)
代码
#include
using namespace std;
const int N=100000+11;
const int inf = 0x3f3f3f3f;
int in[N],out[N],sz=0; int val[N];
vector<int>ve[N];
void dfs(int u,int pre){
in[u]=++sz; val[sz]=u;
for(int i=0;iint v=ve[u][i];
if(v==pre) continue;
dfs(v,u);
}
out[u]=sz;
}
vector<int>T[N<<2];
void Build(int rt,int le,int ri){
if(le==ri ){
T[rt].push_back(val[le]);
return ;
}
int mid=(le+ri)>>1;
Build(rt<<1,le,mid);
Build(rt<<1|1,mid+1,ri);
T[rt].resize(ri-le+1);
merge(T[rt<<1].begin(),T[rt<<1].end(),T[rt<<1|1].begin(),T[rt<<1|1].end(),T[rt].begin());
}
int Query(int rt,int L, int R,int le,int ri,int vv){
if(L==le&&ri==R) return lower_bound(T[rt].begin(),T[rt].end(),vv)-T[rt].begin();
int mid=(L+R)>>1;
if(ri<=mid) return Query(rt<<1,L,mid,le,ri,vv);
else if(le>mid) return Query(rt<<1|1,mid+1,R,le,ri,vv);
else {
return Query(rt<<1,L,mid,le,mid,vv)+Query(rt<<1|1,mid+1,R,mid+1,ri,vv);
}
}
int rot;
int main(){
int n; scanf("%d%d",&n,&rot);
for(int i=1;iint a,b;scanf("%d%d",&a,&b);
ve[a].push_back(b);
ve[b].push_back(a);
}
dfs(rot,-1);
Build(1,1,n);
for(int i=1;i<=n;i++){
if(i!=1) putchar(' ');
int ans=Query(1,1,n,in[i],out[i],i);
printf("%d",ans);
}
return 0;
}