#3636. IIIDX(iiidx)

题目描述

Osu 听过没?那是 Konano 最喜欢的一款音乐游戏,而他的梦想就是有一天自己也能做个独特酷炫的音乐游戏。现在,他在世界知名游戏公司 KONMAI 内工作,离他的梦想也越来越近了。

这款音乐游戏内一般都包含了许多歌曲,歌曲越多,玩家越不易玩腻。同时,为了使玩家在游戏上~~氪更多的金钱~~花更多的时间,游戏一开始一般都不会将所有曲目公开,有些曲目你需要通关某首特定歌曲才会解锁,而且越晚解锁的曲目难度越高。

这一天,Konano 接到了一个任务,他需要给正在制作中的游戏《IIIDX》安排曲目的解锁顺序。游戏内共有 $n$ 首曲目,每首曲目都会有一个难度 $d$,游戏内第 $i$ 首曲目会在玩家 Pass 第 $\left\lfloor \frac i k \right\rfloor$ 首曲目后解锁($\left\lfloor x \right\rfloor$ 为下取整符号)若 $\left\lfloor \frac i k \right\rfloor = 0$,则说明这首曲目**无需解锁**。

举个例子:当 $k = 2$ 时,第 $1$ 首曲目是无需解锁的($\left\lfloor \frac 12 \right\rfloor = 0$),第 $7$ 首曲目需要玩家 Pass 第 $\left\lfloor \frac 72 \right\rfloor = 3$ 首曲目才会被解锁。

Konano 的工作,便是安排这些曲目的顺序,使得每次解锁出的曲子的难度**不低于**作为条件需要玩家通关的曲子的难度,即使得确定顺序后的曲目的难度对于每个 $i$ 满足 $d_i \geq d_{\left\lfloor \frac ik \right\rfloor}$。

数据范围

$1 \le n \le 5 \times 10^5,1 \le k,d \le 10^9$

题解

(此处省略错误贪心)

转化成有根树,然后考虑从 $1 \sim n$ 放数,将 $d$ 从大到小排序。

对于每个数 $x$ ,我们想要其最大,所以我们可以设 $f_i$ 为 $i$ 前还能放的位置,然后找到最靠前的 $i$ ,使得 $min\{f_j\}(j \in [i,n]) \ge size_x$ 即可,然后找到和 $i$ 相同的数的最后一个位置 $j$ ,将 $[j,n]$ 的位置的 $f$ 都减去 $size_x$ 即可,这些操作用线段树维护即可。

注意要把父亲的 $size$ 加回来

代码

#include <bits/stdc++.h>
#define db double
using namespace std;
const int N=5e5+5; db k;
int n,d[N],fa[N],sz[N],pr[N],a[N],in[N<<2],tg[N<<2];
#define Ls u<<1
#define Rs u<<1|1
#define mid ((l+r)>>1)
void build(int u,int l,int r){
    in[u]=l; if (l==r) return;
    build(Ls,l,mid);build(Rs,mid+1,r);
}
void push(int u,int v){tg[u]+=v;in[u]+=v;}
void down(int u){
    push(Ls,tg[u]);push(Rs,tg[u]);tg[u]=0;
}
void upd(int u,int l,int r,int x,int v){
    if (x<=l) return push(u,v);
    if (tg[u]) down(u);
    if (mid>=x) upd(Ls,l,mid,x,v);
    upd(Rs,mid+1,r,x,v);
    in[u]=min(in[Ls],in[Rs]);
}
int find(int u,int l,int r,int v){
    if (l==r) return l+(in[u]<v);
    if (tg[u]) down(u);
    if (in[Rs]>=v) return find(Ls,l,mid,v);
    return find(Rs,mid+1,r,v);
}
int main(){
    cin>>n>>k;
    for (int i=1;i<=n;i++)
        scanf("%d",&d[i]),sz[i]=1,
        fa[i]=(int)((db)i/k);
    sort(d+1,d+n+1);
    reverse(d+1,d+n+1);
    for (int i=n;i;i--)
        sz[fa[i]]+=sz[i],
        pr[i]=d[i]==d[i+1]?pr[i+1]+1:0;
    build(1,1,n);
    for (int j,i=1;i<=n;i++){
        if (fa[i] && fa[i]!=fa[i-1])
            upd(1,1,n,a[fa[i]],sz[fa[i]]-1);
        j=find(1,1,n,sz[i]);
        j+=pr[j];pr[j]++;j-=(pr[j]-1);
        a[i]=j;upd(1,1,n,j,-sz[i]);
    }
    for (int i=1;i<=n;i++)
        printf("%d",d[a[i]]),
        putchar(i<n?' ':'\n');
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/xjqxjq/p/11779086.html
今日推荐