luogu P4364 [九省联考2018]IIIDX

luogu

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

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

考虑先不决定一个点子树内到底取哪些点.先把所有权值从小到大排序,把相同的数合并,然后对每个位置记一个(f_i)表示这个位置以及后面有多少个数没被选定.每次要选(x)的取值的时候,那么选的位置一定要满足(f_ige sz_x),又因为要使得字典序最大,所以就是要选满足(f_ige 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;
}
原文地址:https://www.cnblogs.com/smyjr/p/11518540.html