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;
    }
    

      

  • 相关阅读:
    Flask 中的路由系统
    Flask 中内置的 Session
    Flask中的模板语言jinja2
    Flask 中的 5种返回值
    Redis快速入门
    动态实现前后台分页、翻页按钮、上一页、下一页、首页、末页
    bus.js非父子组件之间通讯
    vue中父子组件之间相互传值
    js实现加减乘除
    禁用微信分享
  • 原文地址:https://www.cnblogs.com/guangheli/p/12416118.html
Copyright © 2011-2022 走看看