[九省联考2018]IIIDX 题解

我被自己菜惊了。

一道小题思路错两次

怕是没救了。

硬是写了2个晚上……

对于每个位置,选能选的最大数。但是要记得预留子树里的数字。

感性地说:如果没有重复数,自然是“挤满”的,但是有重复数后就可能有空余。

离散化,对于每个数字用线段树记录比它大的数中,数的个数减去已确定的不能选的数的个数。

如果两点的数冲突,即两数预留的数中有冲突,那么从这两个数到最大数显然都选了并有数被选两次,即预留的数个数大于区间内总的数个数。

则比两数小的数中必然有数的线段树中的值小于0。

故只要均大于0就合法。以此二分找当前能选的最大数即可。

另外注意:每次新到一个父节点要把其预留的数“释放”给子节点。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn = 2500005;
const int inf = 0x3f3f3f3f;
int n, d[maxn], tm, y[maxn], bigger[maxn];
int ans[maxn], c[maxn], kk[maxn], lsum[maxn];
double k;

struct atree {
    #define ls (x*2)
    #define rs (x*2+1)
    int minn[maxn], tag[maxn];
    void down(int x) {
        minn[ks]+=tag[x]; tag[ls]+=tag[x];
        minn[rs]+=tag[x]; tag[rs]+=tag[x];
        tag[x]=0;
    }
    void add(int x, int l, int r, int a, int b, int k) {
        if(l > b || a > r) return;
        if(a <= l && r <= b) { minn[x]+=k; tag[x]+=k; return; }
        int mid=(l+r)/2;
        down(x);
        add(ls, l, mid, a, b, k);
        add(rs, mid+1, r, a, b, k);
        minn[x]=min(minn[x*2], minn[x*2+1]);
        return;
    }
    int count(int x, int l, int r, int a, int b) {
        if(l > b || a > r) return inf;
        if(a <= l && r <= b) { return minn[x]; }
        int mid=(l+r)/2, t;
        down(x);
        t=min(count(ls, l, mid, a, b), count(rs, mid+1, r, a, b));
        minn[x]=min(minn[x*2], minn[x*2+1]);
        return t;
    }
} T;

inline int find_p(int x) {
    int l=1, r=tm, mid;
    while(l < r) {
        mid=(l+r+1)/2;
        if(T.count(1, 1, n+1, 1, mid) < x) r=mid-1;
        else l=mid;
    }
    return l;
}

int main() {
    int i, t, tt, sum=0, tc=0;
    cin>>n>>k;
    for(i=1; i <= n; i++) cin>>d[i];
    sort(d+1, d+1+n);
    for(i=1; i <= n; i++) {
        if(i == 1 || d[i] != d[i-1]) tm++, y[tm]=d[i];
        T.add(1, 1, n+1, 1, tm, 1);
        bigger[i]=1;
    }
    for(i=n; i >= 1; i--) {
        t=(double)i*1.0/k;
        bigger[t]+=bigger[i];
    }
    for(i=1; i <= n; i++) {
        t=(double)i*1.0/k;
        tt=(double)(i-1.0)*1.0/k;
        if(tt != t && t != 0) T.add(1, 1, n+1, 1, ans[t]-1+1, bigger[t]-1);
        t=find_p(bigger[i]);
        ans[i]=t;
        T.add(1, 1, n+1, 1, t-1+1, -bigger[i]);
        cout<<y[t]<<' ';
    }
    return 0;
}

 

posted @ 2019-09-07 11:16  悲风吟客  阅读(129)  评论(0编辑  收藏  举报