• 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;
    }
    
  • 相关阅读:
    java基础之冒泡排序
    java基础之HashSet如何保证对象的唯一性
    java基础之日期时间工具类
    java基础之抽象类和接口的区别
    java tomcat报错: Starting Tomcat v7.0 Server at localhost' has encountered a problem问题
    [bzoj 4196][NOI 2015]软件包管理器
    [bzoj 4034][HAOI 2015]树上操作
    [bzoj 1012][JSOI2008]最大数maxnumber
    详解Trie
    [bzoj 1047][HAOI2007]理想的正方形
  • 原文地址:https://www.cnblogs.com/smyjr/p/11518540.html
Copyright © 2020-2023  润新知