zoukankan      html  css  js  c++  java
  • CF1039D You Are Given a Tree 根号分治+二分

    如果 $k$ 值确定的话,我们直接来一个 $O(n)$ 的贪心就行.  

    那么我们就将 $k$ 分为大于 $B$ 和小于 $B$ 两部分处理.  

    对于小于 $B$ 的部分,暴力处理,复杂度为 $O(nB)$.  

    对于大于 $B$ 的部分,取值分别为 $[0,frac{n}{B}]$ 且依次递减.  

    那么我们就可以二分每种取值的区间.   

    由于有 $frac{n}{B}$ 种取值,计算每个取值区间为 $O(n log n)$,故这部分复杂度为 $frac{n}{B} n log n$    

    一般来说,这个 $B$ 取 200 左右是比较优的. 

    code: 

    #include <bits/stdc++.h>    
    #define B 203   
    #define N 100006 
    #define ll long long   
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;  
    int n,edges,tim;  
    int hd[N],to[N<<1],nex[N<<1],f[N],vis[N],maxx[N],po[N],fa[N];    
    void add(int u,int v) 
    {
    	nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;  
    }   
    void dfs(int x,int ff) 
    { 
    	po[++tim]=x,fa[x]=ff;   
    	for(int i=hd[x];i;i=nex[i])   
    		if(to[i]!=ff)  
    			dfs(to[i],x);   
    }       
    int solve(int x) 
    {      
    	f[x]=0;      
    	int i,j;  
    	memset(vis,0,sizeof(vis));   
    	for(i=1;i<=n;++i) maxx[i]=1;  
    	for(i=tim;i>=1;--i) 
    	{     
    		int u=po[i];                  
    		if(fa[u]&&!vis[u])      
    		{
    			if(vis[fa[u]]==0) 
    			{
    				if(maxx[fa[u]]+maxx[u]>=x)    
    					++f[x],maxx[fa[u]]=0,vis[fa[u]]=1;       
    				else          
    					maxx[fa[u]]=max(maxx[fa[u]],maxx[u]+1);    
    			}                    
    		}
    	}    
    	return f[x];             
    }
    void init(int M) 
    {   
    	int i,j;     
    	f[1]=n;     
    	for(i=2;i<=M;++i)    
    	   	solve(i);     
    }
    int main() 
    { 
    	// setIO("input");  
    	int i,j;       
    	scanf("%d",&n);   
    	for(i=1;i<n;++i) 
    	{
    		int x,y;  
    		scanf("%d%d",&x,&y);  
    		add(x,y),add(y,x);  
    	}             
    	dfs(1,0);   
    	init(min(n,B));    
    	if(n<=B) 
    	{
    		for(i=1;i<=n;++i)  
    			printf("%d
    ",f[i]);  
    	}   
    	else 
    	{
    	    int An;  
    		for(i=B+1;i<=n;i=An+1) 
    		{ 
    			An=i;  
    			int l=i,r=n;   
    			int tmp=solve(l);  
    			while(l<=r) 
    			{  
    				int mid=(l+r)>>1;   
    				if(solve(mid)==tmp)    
    					An=mid,l=mid+1;   
    				else  
    					r=mid-1;   
    			}    
    			for(j=i;j<=An;++j) 
    				f[j]=tmp;  
    		}
    		for(i=1;i<=n;++i)  
    			printf("%d
    ",f[i]);  
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    [转载]Silverlight实用窍门系列:71.Silverlight的Style
    vs2010中自动实现抽象方法
    js拖拽案例、自定义滚动条
    js同步、异步、延时、无阻塞加载
    Aspose Words、Excel(xlsx)导出等操作
    echarts笔记
    IIS中报错弹出调试,系统日志-错误应用程序名称: w3wp.exe,版本: 8.5.9600.16384,时间戳: 0x5215df96(360主机卫士)
    EasyUI所有方案案例整合篇
    windows service创建使用整合
    Oracle问题整合
  • 原文地址:https://www.cnblogs.com/guangheli/p/12416118.html
Copyright © 2011-2022 走看看