您的位置:首页 > 其它

蓝桥杯模拟赛 青出于蓝而胜于蓝

2018-01-30 09:57 267 查看
武当派一共有 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序列+树状数组
利用dfs序列把树序列化,并可以用时间戳来维护一个非叶子节点的子树。对于一个区间 求这个区间内比某个值要小的值的个数,利用权值线段树的思想
代码:


#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int maxn=100010;
int n,m;
vector<int> edge[maxn];
int in[maxn*2],out[maxn*2];
int ret;
int tree[maxn*2];
int lowbit(int t)
{
return t&(-t);
}
void up(int x,int y)
{
for(int i=x;i<=n;i+=lowbit(i))
tree[i]+=y;
}
int getsum(int x)
{
int ans=0;
for(int i=x;i>0;i-=lowbit(i)) ans+=tree[i];
return ans;
}
void init()
{
memset(tree,0,sizeof(tree));
ret=0;
for(int i=0;i<=n;i++) edge[i].clear();
}
void dfs(int u,int fa)
{
in[u]=++ret;
int len=edge[u].size();
for(int i=0;i<len;i++)
{
if(edge[u][i]!=fa)
{
dfs(edge[u][i],u);
}
}
out[u]=ret;
}
int main()
{
scanf("%d %d",&n,&m);
init();
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d %d",&x,&y);
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs(m,m);
for(int i=1;i<=n;i++)
{
cout<<getsum(out[i])-getsum(in[i]);
if(i!=n) cout<<" ";
up(in[i],1);
}
cout<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: