luogu P4364 [九省联考2018]IIIDX

luogu

注意到这个森林的bfs序就是从\(1\)\(n\),然后要使得字典序最大,那么显然要从\(1\)\(n\)依次考虑放什么数.有一个\(d\)全部不同的贪心,就是维护某个点子树内可用的权值集合,首先这个点只能取最小的,然后按顺序枚举儿子,要使得字典序最大,那就要让前面的点能取的权值尽量大,又因为\(d_x\ge d_{fa_x}\),所以一个点选的位置最靠后可以在从小到大倒数第\(sz_x\)个位置,然后后面的值就分给他的儿子子树.删掉后面一些位置接着做就行了

注意有\(d\)相等的时候这个是假的,因为某个点可以通过将自己取值所在位置的前移,使得自己取值尽可能大的情况下后面一个点取值可以更大.不过现在貌似没有一个可以直接瞎贪心的做法

考虑先不决定一个点子树内到底取哪些点.先把所有权值从小到大排序,把相同的数合并,然后对每个位置记一个\(f_i\)表示这个位置以及后面有多少个数没被选定.每次要选\(x\)的取值的时候,那么选的位置一定要满足\(f_i\ge sz_x\),又因为要使得字典序最大,所以就是要选满足\(f_i\ge sz_x\)并且权值最大(位置最右边)的位置,选了这个位置就是这个点的值,然后后面还要留出一些位置给子树选,所以\(f_1\)\(f_i\)要减去\(sz_x\).然后模拟这个过程\(n\)次即可得到答案

注意一下,首先\(f_i\)是单调不增的,因为\(f_i\)本质上是一个后缀和,所以说真正的\(f_i\)应该是\(\min_{j=1}^{i} f_j\);并且在做到一个点的时候,如果它是其父亲的第一个儿子,那么要消除它父亲的影响(也就是\(f_1\)\(f_{ans_{fa_x}}\)加上\(sz_{fa_x}-1\)),因为那个\(sz_{fa_x}-1\)是被父亲占用的,现在我们要把这一部分留给子树去选

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=5e5+10;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
#define mid ((l+r)>>1)
int mi[N<<2],tg[N<<2];
void psup(int o){mi[o]=min(mi[o<<1],mi[o<<1|1]);}
void ad(int o,int x){mi[o]+=x,tg[o]+=x;}
void psdn(int o){if(tg[o]) ad(o<<1,tg[o]),ad(o<<1|1,tg[o]),tg[o]=0;}
void modif(int o,int l,int r,int ll,int rr,int x)
{
    if(ll<=l&&r<=rr){ad(o,x);return;}
    psdn(o);
    if(ll<=mid) modif(o<<1,l,mid,ll,rr,x);
    if(rr>mid) modif(o<<1|1,mid+1,r,ll,rr,x);
    psup(o);
}
int quer(int o,int l,int r,int w)
{
    if(l==r) return l-(mi[o]<w);
    psdn(o);
    int an=mi[o<<1]>=w?quer(o<<1|1,mid+1,r,w):quer(o<<1,l,mid,w);
    psup(o);
    return an;
}

db kk;
int n,a[N],an[N],b[N],m,sz[N],fa[N];
bool v[N];
void bui(int o,int l,int r)
{
    if(l==r){mi[o]=b[l];return;}
    bui(o<<1,l,mid),bui(o<<1|1,mid+1,r);
    psup(o);
}

int main()
{
    n=rd();
    scanf("%lf",&kk);
    for(int i=1;i<=n;++i) a[i]=rd();
    sort(a+1,a+n+1);
    for(int i=1;i<=n;++i)
    {
        if(a[i]!=a[i-1]) ++m;
        ++b[m];
    }
    for(int i=m;i;--i) b[i]+=b[i+1];
    bui(1,1,m);
    unique(a+1,a+n+1);
    for(int i=1;i<=n;++i)
    {
        fa[i]=(int)((db)i/kk);
        sz[i]=1;
    }
    for(int i=n;i;--i)
        sz[fa[i]]+=sz[i];
    for(int i=1;i<=n;++i)
    {
        if(!v[fa[i]])
            if(an[fa[i]]) modif(1,1,m,1,an[fa[i]],sz[fa[i]]-1);
        v[fa[i]]=1;
        int p=quer(1,1,m,sz[i]);
        modif(1,1,m,1,p,-sz[i]);
        printf("%d ",a[an[i]=p]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/smyjr/p/11518540.html