zoukankan      html  css  js  c++  java
  • [BZOJ5249][九省联考2018]IIIDX:线段树+贪心

    分析

    GXZlegend orz

    构造出一组合法的解并不是难事,但是我们需要输出的是字典序最大的解。

    字典序最大有另一种理解方式,就是让越小的数尽量越靠后。

    我们从树的根结点出发,从1开始填数,构造出来的一定是一组合法的解。

    对于每种相同的数,可以通过线段树上二分逐个确定他们的最优位置,具体细节可以看代码。

    代码

    #include <bits/stdc++.h>
    #define rin(i,a,b) for(register int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(register int i=(a);i>=(b);--i)
    #define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
    typedef long long LL;
    using std::cin;
    using std::cout;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int MAXN=500005;
    
    int n,d[MAXN];
    int ecnt,head[MAXN],siz[MAXN],ans[MAXN];
    double k;
    int sum[MAXN<<2],loc,ql,qr,kk;
    
    struct Edge{
    	int to,nxt;
    }e[MAXN<<1];
    
    inline void add_edge(int bg,int ed){
    	++ecnt;
    	e[ecnt].to=ed;
    	e[ecnt].nxt=head[bg];
    	head[bg]=ecnt;
    }
    
    #define mid ((l+r)>>1)
    #define lc (o<<1)
    #define rc ((o<<1)|1)
    
    void upd(int o,int l,int r){
    	if(l==r){
    		sum[o]+=kk;
    		return;
    	}
    	if(loc<=mid) upd(lc,l,mid);
    	else upd(rc,mid+1,r);
    	sum[o]=sum[lc]+sum[rc];
    }
    
    int query(int o,int l,int r){
    	if(l==r) return l;
    	if(sum[rc]>=kk) return query(rc,mid+1,r);
    	else return kk-=sum[rc],query(lc,l,mid);
    }
    
    #undef mid
    #undef lc
    #undef rc
    
    int main(){
    	n=read();
    	scanf("%lf",&k);
    	rin(i,1,n) d[i]=read(),siz[i]=1;
    	std::sort(d+1,d+n+1);
    	rin(i,1,n) add_edge((int)floor(i/k),i);
    	irin(i,n,1) siz[(int)floor(i/k)]+=siz[i];
    	trav(i,0){int ver=e[i].to;loc=ver,kk=siz[ver];upd(1,1,n);}
    	int cnt=1;
    	rin(i,2,n+1){
    		if(d[i]==d[i-1]){#include <bits/stdc++.h>
    #define rin(i,a,b) for(register int i=(a);i<=(b);++i)
    #define irin(i,a,b) for(register int i=(a);i>=(b);--i)
    #define trav(i,a) for(register int i=head[a];i;i=e[i].nxt)
    typedef long long LL;
    using std::cin;
    using std::cout;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int MAXN=500005;
    
    int n,d[MAXN];
    int ecnt,head[MAXN],siz[MAXN],ans[MAXN];
    double k;
    int sum[MAXN<<2],loc,ql,qr,kk;
    
    struct Edge{
    	int to,nxt;
    }e[MAXN<<1];
    
    inline void add_edge(int bg,int ed){
    	++ecnt;
    	e[ecnt].to=ed;
    	e[ecnt].nxt=head[bg];
    	head[bg]=ecnt;
    }
    
    #define mid ((l+r)>>1)
    #define lc (o<<1)
    #define rc ((o<<1)|1)
    
    void upd(int o,int l,int r){
    	if(l==r){
    		sum[o]+=kk;
    		return;
    	}
    	if(loc<=mid) upd(lc,l,mid);
    	else upd(rc,mid+1,r);
    	sum[o]=sum[lc]+sum[rc];
    }
    
    int query(int o,int l,int r){
    	if(l==r) return l;
    	if(sum[rc]>=kk) return query(rc,mid+1,r);
    	else return kk-=sum[rc],query(lc,l,mid);
    }
    
    #undef mid
    #undef lc
    #undef rc
    
    int main(){
    	n=read();
    	scanf("%lf",&k);
    	rin(i,1,n) d[i]=read(),siz[i]=1;
    	std::sort(d+1,d+n+1);
    	rin(i,1,n) add_edge((int)floor(i/k),i);
    	irin(i,n,1) siz[(int)floor(i/k)]+=siz[i];
    	trav(i,0){int ver=e[i].to;loc=ver,kk=siz[ver];upd(1,1,n);}
    	int cnt=1;
    	rin(i,2,n+1){
    		if(d[i]==d[i-1]){
    			++cnt;
    			continue;
    		}
    		irin(j,cnt,1){
    			kk=j;int ret=query(1,1,n);ans[ret]=d[i-1];
    			loc=ret,kk=-siz[ret];upd(1,1,n);
    			trav(l,ret){
    				int ver=e[l].to;
    				loc=ver,kk=siz[ver];upd(1,1,n);
    			}
    		}
    		cnt=1;
    	}
    	rin(i,1,n) printf("%d ",ans[i]);
    	printf("
    ");
    	return 0;
    }
    			++cnt;
    			continue;
    		}
    		irin(j,cnt,1){
    			kk=j;int ret=query(1,1,n);ans[ret]=d[i-1];
    			loc=ret,kk=-siz[ret];upd(1,1,n);
    			trav(l,ret){
    				int ver=e[l].to;
    				loc=ver,kk=siz[ver];upd(1,1,n);
    			}
    		}
    		cnt=1;
    	}
    	rin(i,1,n) printf("%d ",ans[i]);
    	printf("
    ");
    	return 0;
    }
    
  • 相关阅读:
    jquery中$.get()提交和$.post()提交有区别吗?
    数据库连接池的原理。为什么要使用连接池。
    execute,executeQuery,executeUpdate的区别是什么?
    数据库的三级模式与二级映像
    KMP算法(超容易理解的next数组求法)
    软件危机(含通俗理解帮助记忆)
    O(1)复杂度求一个栈的最小值
    操作系统进程状态模型
    判断单链表是否有环,如果有环则找到其环的入口
    两个单链表判断是否相交
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10447535.html
Copyright © 2011-2022 走看看