Codeforces738E-Subordinates(贪心+构造)

来源:互联网 发布:魔豆软件 编辑:程序博客网 时间:2024/05/20 05:26

题目链接

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