Codeforces738E-Subordinates(贪心+构造)

14 篇文章 0 订阅
4 篇文章 0 订阅

题目链接

http://codeforces.com/contest/738/problem/E

思路

所有员工的上下级关系构成一棵树,假设一个员工他有x个superior,那么他就在这棵树的x + 1层,则1, 2, 3, ……, x层至少存在一个员工
我们先不考虑0,那么就将这道题转化成了:我们先将原来的序列排序,得到一个LIS,现在我们可以改变若干个数,使这个序列变成连续的LIS(即任意两个相邻的数相差不超过1的LIS,如:1, 2, 2, 3, 3, 3, 4, 5)
那么我们原来的序列是个离散的LIS,如这个序列:2, 2, 3, 3, 4, 6
可以这样看:
这里写图片描述
有颜色的代表有若干个这个数字,无颜色的代表为空,我们需要做的是:填充无颜色的,最后得到这个序列的最大数字为x,那么1到x应全部有颜色
我们可以这样贪心的去想:假设我们要去填充1,我们选6去填充它和选2去填充它都只消耗1个价值,但是如果我们选6去填充它的话,6只有一个,被消耗掉了,这时候1到4全是有颜色的了,此时1到4已经是一个连续的LIS,不用再填充6了。
于是可以得到我们的贪心方法:设有颜色的为集合A,无颜色的为集合B,从A中选最大的,依次去填充B里面最小的,直到A中最大的 < B中最小的

细节

  1. 集合A用大顶堆去维护,B用小顶堆去维护,那么我们可以分析出时间复杂度最大为B中元素的个数,即O(N)
  2. chief元素要单独处理

代码

#include <bits/stdc++.h>

using namespace std;

inline int in() {int x; scanf("%d", &x); return x;}
#define pr(x) {cout << #x << ' ' << x << endl;}

const int maxn = 200000 + 5;
int a[maxn], s, n, vis[maxn];
int tot = 0;
priority_queue<int> Q1;
priority_queue<int, vector<int>, greater<int> > Q2;

int main() {
    n = in(), s = in();
    for (int i = 0; i < n; i++) a[i] = in();
    if (a[--s] != 0) a[s] = 0, tot++;
    sort(a, a + n);
    int maxa = a[n - 1];
    for (int i = 0; i < n; i++) vis[a[i]]++;
    for (int i = 0; i <= maxa; i++) {
        if (!vis[i]) Q2.push(i);
        else Q1.push(i);
    }
    if (vis[0] > 1) {
        while (1) {
            if (Q2.empty()) {
                tot += (vis[0] - 1);
                vis[0] = 1;
                break;
            }
            if (vis[0] == 1) break;
            vis[0]--;
            Q2.pop();
            tot++;
        }
    }
    while (1) {
        if (Q2.empty() || Q1.empty() || Q2.top() > Q1.top()) break;
        tot++;
        Q2.pop();
        int t = Q1.top(); 
        vis[t]--;
        if (vis[t] == 0) Q1.pop();
    }
    cout << tot << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值