• LOJ #2472. 「九省联考 2018」IIIDX 贪心+线段树


    显然,如果不出现重复数字的话直接贪心填就是正确的.   

    然而,当出现重复数字时这个贪心就错了.      

    将这个问题抽象成树是显然的.  

    我们先将所有数从大到小排.  

    对于大小为 $size[i]$ 的 $i$ 来说,肯定选当前能选的第 $size[i]$ 大的. (设为 $x$)  

    那么,选择完 $x$ 后,显然 $x$ 前必须给 $i$ 预留 $size[i]$ 个位置.  

    那么假设每个点都有 $f[i]$ 表示 $i$ 前最多能填多少个数,我们显然选择满足 $size[i]<=f[j]$ 且最大的 $i$.   

    这个找 $j$ 的过程可以在线段树上二分,然后找到位置后打上一个标记即可. 

    code: 

    #include <bits/stdc++.h>    
    #define ll long long 
    #define lson now<<1 
    #define rson now<<1|1     
    #define N 500006  
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;        
    int minn[N<<2],tag[N<<2],size[N];    
    void build(int l,int r,int now) 
    {
    	if(l==r)  { minn[now]=l; return; }   
    	int mid=(l+r)>>1;  
    	build(l,mid,lson),build(mid+1,r,rson);   
    	minn[now]=min(minn[lson],minn[rson]);  
    }   
    void mark(int x,int v) 
    {
    	tag[x]+=v;   
    	minn[x]+=v; 
    } 
    void pushdown(int now) 
    {
    	if(tag[now]) 
    	{
    		mark(lson,tag[now]);  
    		mark(rson,tag[now]);  
    		tag[now]=0; 
    	}
    }
    void update(int l,int r,int now,int L,int R,int v) 
    {    
    	if(l>=L&&r<=R)  
    	{
    		mark(now,v);   
    		return; 
    	}
    	pushdown(now); 
    	int mid=(l+r)>>1;   
    	if(L<=mid)   
    		update(l,mid,lson,L,R,v);  
    	if(R>mid)  
    		update(mid+1,r,rson,L,R,v);    
    	minn[now]=min(minn[lson],minn[rson]);   
    }
    int query(int l,int r,int now,int k) 
    {
    	if(l==r)  return minn[now]<k?(l+1):l;  
    	int mid=(l+r)>>1;   
    	pushdown(now);   
    	if(minn[rson]>=k)     
    		return query(l,mid,lson,k);  
    	else 
    		return query(mid+1,r,rson,k);    
    }   
    int w[N],val[N],nxt[N],fa[N],clr[N],ans[N];     
    bool cmp(int a,int b) { return a>b; }    
    int main() 
    { 
    	// setIO("input");    
    	int i,j,n;  
    	double tmp;  
    	scanf("%d%lf",&n,&tmp);   
    	for(i=1;i<=n;++i)     
    		scanf("%d",&w[i]);     
    	sort(w+1,w+1+n,cmp);              
    	for(i=n;i>=1;--i) 
    	{
    		++size[i];    
    		nxt[i]=i;    
    		fa[i]=(int)(1.0*i/tmp);     
    		size[fa[i]]+=size[i];   
    		if(i!=n&&w[i]==w[i+1])  
    			nxt[i]=nxt[i+1];  
    	}
    	build(1,n,1);  
    	for(i=1;i<=n;++i) 
    	{ 
    		if(fa[i]&&!clr[fa[i]])                 
    		{ 
    			update(1,n,1,ans[fa[i]],n,size[fa[i]]-1);     
    			clr[fa[i]]=1;         
    		}
    		ans[i]=query(1,n,1,size[i]);                    
    		ans[i]=nxt[ans[i]];      
    		update(1,n,1,ans[i],n,-size[i]);       
    	}
    	for(i=1;i<=n;++i)  
    		printf("%d ",w[ans[i]]);  
    	return 0;
    }
    

      

  • 相关阅读:
    C#中TreeView组件使用方法初步
    DataList编辑、更新、取消、删除、分页
    使用JMeter做web应用的压力测试
    再读Struts1.3.5 User Guide 3 Building Control Components
    Tomcat DBCP Connection Pool Abandon Feature
    在Linux调试web应用时,如何查看System.out.println的输出?
    再读Struts1.3.5 User Guide 4 Configuring Applications
    一篇关于web.xml配置的详细说明
    再读Struts1.3.5 User Guide 1 Building Model Components
    Struts下html:select可以多选时的处理方法
  • 原文地址:https://www.cnblogs.com/guangheli/p/12451790.html
Copyright © 2020-2023  润新知