题意:中文
武当派一共有 n 人,门派内 n 人按照武功高低进行排名,武功最高的人排名第 1,次高的人排名第 2,... 武功最低的人排名第 n。现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师父,每个人可能有多个徒弟。
我们知道,武当派人才辈出,连祖师爷的武功都只能排行到 p。也就是说徒弟的武功是可能超过师父的,所谓的青出于蓝胜于蓝。
请你帮忙计算每个人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超过了他自己。
思路:对于面对树形结构的题我们如果把他变成线性就好整了多了,那么怎样将他变成线性的呢,我们用dfs序,开两个数组,一个in一个out,分别表示的是它深搜时的编码和深搜结束后的编码,我们in[x]~out[x]表示的就是x点管辖的区间(也就是x点的子孙),之后的问题就很好解决了,就是求一下x管辖区间内的逆序数时多少吗
上代码把:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100000+10;
struct node
{
int to,nex;
}edg[maxn];
vector<int>V[maxn];
int vis[maxn],in[maxn],out[maxn],ans[maxn];
int sum[maxn];
int n,p,a,b,cnt;
int lowbit(int x)
{
return x&(-x);
}
void add(int x)
{
//printf("X = %d\n",x);
while(x<=n)
{
sum[x]++;
x += lowbit(x);
// printf("X = %d\n",x);
}
}
int query(int x)
{
int ans = 0 ;
while(x)
{
ans+=sum[x];
x -= lowbit(x);
}
return ans;
}
void dfs(int u)
{
if(vis[u]) return ;
vis[u] = 1;
in[u] = ++ cnt;
for(int i = 0 ; i < V[u].size();i++)
{
int v = V[u][i];
dfs(v);
}
out[u] = cnt;
}
int main()
{
cin>>n>>p;
memset(vis,0,sizeof(vis));
cnt = 0;
for(int i = 0 ; i < n-1;i++)
{
cin>>a>>b;
V[a].push_back(b);
V[b].push_back(a);
}
dfs(p);
for(int i = n ; i >= 1 ; i--)
{
ans[i] = out[i] - in[i] -(query(out[i]) - query(in[i]));
add(in[i]);
}
for(int i = 1 ; i <= n-1 ; i++)
{
printf("%d ",ans[i]);
}
printf("%d\n",ans[n]);
}