[Luogu P3605] [BZOJ 4756] [USACO17JAN] Promotion Counting晋升者计数

洛谷传送门
BZOJ传送门

题目描述

奶牛们又一次试图创建一家创业公司,还是没有从过去的经验中吸取教训–牛是可怕的管理者!

为了方便,把奶牛从 1N(1N100,000) 1 ⋯ N ( 1 ≤ N ≤ 100 , 000 ) 编号,把公司组织成一棵树, 1 1 号奶牛作为总裁(这棵树的根节点)。除了总裁以外的每头奶牛都有一个单独的上司(它在树上的 “双亲结点”)。所有的第 i 头牛都有一个不同的能力指数 p(i) p ( i ) ,描述了她对其工作的擅长程度。如果奶牛 i i 是奶牛 j 的祖先节点(例如,上司的上司的上司),那么我们我们把奶牛 j j 叫做 i 的下属。

不幸地是,奶牛们发现经常发生一个上司比她的一些下属能力低的情况,在这种情况下,上司应当考虑晋升她的一些下属。你的任务是帮助奶牛弄清楚这是什么时候发生的。简而言之,对于公司的中的每一头奶牛 i i ,请计算其下属 j 的数量满足 p(j)>p(i) p ( j ) > p ( i )

输入输出格式

输入格式:

输入的第一行包括一个整数 N N

接下来的 N 行包括奶牛们的能力指数 p(1)p(N) p ( 1 ) ⋯ p ( N ) . 保证所有数互不相同,在区间 1109 1 ⋯ 10 9 之间。

接下来的 N1 N − 1 行描述了奶牛 2N 2 ⋯ N 的上司(双亲节点)的编号。再次提醒, 1 1 号奶牛作为总裁,没有上司。

输出格式:

输出包括 N 行。输出的第 i i 行应当给出有多少奶牛 i 的下属比奶牛 i i 能力高。

输入输出样例

输入样例#1:

5
804289384
846930887
681692778
714636916
957747794
1
1
2
3

输出样例#1:

2
0
1
0
0

解题分析

先考虑序列上怎么做, 显然直接BIT统计逆序对。

现在有了深度这个限制, 我们就按照 DFS D F S 的顺序, 依次处理。 由于我们是加入 BIT B I T 的时候是按其能力值的排名加入的, 而一个节点上面也有能力比它小的点, 所以我们先记录下来, 在 DFS D F S 完成的时候再作差消除即可。

另外, BIT B I T 统计的是前缀和, 所以排名第 i i 的点的实际插入位置为Ni+1

代码如下:

#include <cstdio>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 100050
#define lbt(i) (i & -i)
template <class T>
IN void in(T &x)
{
    x = 0; R char c = gc;
    for (; !isdigit(c); c = gc);
    for (;  isdigit(c); c = gc)
    x = (x << 1) + (x << 3) + c - 48;
}
struct INFO {int id, val;} dat[MX];
IN bool operator < (const INFO &x, const INFO &y)
{return x.val < y.val;}
int rk[MX], dot, head[MX], ans[MX], cnt, tree[MX];
struct Edge {int to, nex;} edge[MX << 1];
IN void add (R int from, R int to)
{edge[++cnt] = {to, head[from]}, head[from] = cnt;}
namespace BIT
{
    IN void add(R int now, R int del)
    {W (now <= dot) tree[now] += del, now += lbt(now);}
    IN int sum(R int now)
    {
        int ret = 0;
        W (now) ret += tree[now], now -= lbt(now);
        return ret;
    }
}
void DFS(R int now)
{
    int sur = BIT::sum(rk[now]);
    for (R int i = head[now]; i; i = edge[i].nex)
    DFS(edge[i].to);
    ans[now] = BIT::sum(rk[now]) - sur;
    BIT::add(rk[now], 1);
}
int main(void)
{
    in(dot); int a;
    for (R int i = 1; i <= dot; ++i) in(dat[i].val), dat[i].id = i;
    std::sort(dat + 1, dat + 1 + dot);
    for (R int i = 1; i <= dot; ++i) rk[dat[i].id] = dot - i + 1;
    for (R int i = 2; i <= dot; ++i) in(a), add(a, i);
    DFS(1);
    for (R int i = 1; i <= dot; ++i) printf("%d\n", ans[i]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值