5249: [2018多省省队联测]IIIDX

5249: [2018多省省队联测]IIIDX

链接

分析:

  贪心。

  将给定的权值从大到小排序,从第一个往后挨个赋值,考虑第i个位置可以赋值那些树。首先满足前面必须至少有siz[i]个权值没选,如果存在相同的数,尽量往后选。

  那么可以给每个权值记录一个值F[i],表示i左边可以选多少个权值了。还要和后面的取一个最小值才是真正的能选多少个。

  在线段树上分治找到这个位置。

  注意在bzoj上,fa[i]=int(1.0*i/k) 有精度误差,而写成floor就可以了。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 500005;
int Mn[N << 2], tag[N << 2], R[N], fa[N], siz[N], ans[N], cnt[N], w[N];

inline bool cmp(int x,int y) { return x > y; }
inline void pushup(int rt) { Mn[rt] = min(Mn[rt << 1], Mn[rt << 1 | 1]); }
inline void pushdown(int rt) {
    tag[rt << 1] += tag[rt];tag[rt << 1 | 1] += tag[rt];
    Mn[rt << 1] += tag[rt];Mn[rt << 1 | 1] += tag[rt];
    tag[rt] = 0;
}
void build(int l,int r,int rt) {
    tag[rt] = 0;
    if (l == r) {
        Mn[rt] = l; return ;
    }
    int mid = (l + r) >> 1;
    build(lson); build(rson);
    pushup(rt);
}
void update(int l,int r,int rt,int L,int R,int v) {
    if (L <= l && r <= R) {
        tag[rt] += v; Mn[rt] += v; return ;
    }
    if (tag[rt]) pushdown(rt);
    int mid = (l + r) >> 1;
    if (L <= mid) update(lson, L, R, v);
    if (R > mid) update(rson, L, R, v);
    pushup(rt);
}
int query(int l,int r,int rt,int x) {
    if (l == r) return l + (Mn[rt] < x);
    if (tag[rt]) pushdown(rt);
    int mid = (l + r) >> 1;
    if (x <= Mn[rt << 1 | 1]) return query(lson, x);
    else return query(rson, x);
}
int main() {
    int n = read();
    double k; scanf("%lf", &k);
    for (int i = n; i >= 1; --i) 
        fa[i] = floor(1.0 * i / k), siz[i] ++, siz[fa[i]] += siz[i];
    for (int i = 1; i <= n; ++i) w[i] = read();
    sort(w + 1, w + n + 1, cmp);
    build(1, n, 1);
    for (int i = n; i >= 1; --i) {
        if (w[i] == w[i + 1]) R[i] = R[i + 1];
        else R[i] = i;
    }
    for (int i = 1; i <= n; ++i) {
        if (fa[i] && fa[i] != fa[i - 1]) 
            update(1, n, 1, ans[fa[i]], n, siz[fa[i]] - 1);
        int x = query(1, n, 1, siz[i]);
        x = R[x]; cnt[x] ++; x -= cnt[x] - 1; ans[i] = x;
        update(1, n, 1, x, n, -siz[i]);
    }
    for (int i = 1; i <= n; ++i) printf("%d ", w[ans[i]]);
    return 0;
}
原文地址:https://www.cnblogs.com/mjtcn/p/10359598.html