• BZOJ 2117: [2010国家集训队]Crash的旅游计划 动态点分治+二分


    感觉现在写点分治可快了~

    二分答案,就可以将求第 $k$ 大转换成一个判断问题,直接拿点分树判断一下就行了. 

    #include <cstdio> 
    #include <vector> 
    #include <algorithm>  
    #define N 100004 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;   
    int n,edges,K; 
    int hd[N],to[N<<1],nex[N<<1],val[N<<1];  
    void add(int u,int v,int c)
    {
    	nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; 
    }   
    namespace tree
    { 
    	int size[N],son[N],fa[N],top[N],dep[N],dis[N]; 
    	void dfs1(int u,int ff)
    	{ 
    		fa[u]=ff,size[u]=1; 
    		for(int i=hd[u];i;i=nex[i]) 
    			if(to[i]!=ff) 
    			{ 
    				dep[to[i]]=dep[u]+1,dis[to[i]]=dis[u]+val[i]; 
    				dfs1(to[i],u); 
    				size[u]+=size[to[i]]; 
    				if(size[to[i]]>size[son[u]]) son[u]=to[i]; 
    			}
    	} 
    	void dfs2(int u,int tp)
    	{    
    		top[u]=tp; 
    		if(son[u]) dfs2(son[u],tp); 
    		for(int i=hd[u];i;i=nex[i]) 
    			if(to[i]!=fa[u]&&to[i]!=son[u]) 
    				dfs2(to[i],to[i]);      
    	}
    	int LCA(int x,int y)
    	{
    		while(top[x]!=top[y]) 
    			dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]]; 
    		return dep[x]<dep[y]?x:y;    
     	} 
     	int Dis(int x,int y)
     	{
     		return dis[x]+dis[y]-(dis[LCA(x,y)]<<1);    
     	} 
    };  
    vector<int>F[N],G[N];     
    int root,sn; 
    int mx[N],size[N],vis[N],Fa[N];      
    void dfs(int u,int ff)
    {
    	size[u]=1; 
    	for(int i=hd[u];i;i=nex[i]) 
    		if(!vis[to[i]]&&to[i]!=ff) 
    			dfs(to[i],u),size[u]+=size[to[i]]; 
    } 
    void getroot(int u,int ff)
    {
    	size[u]=1,mx[u]=0; 
    	for(int i=hd[u];i;i=nex[i]) 
    		if(to[i]!=ff&&!vis[to[i]])  
    			getroot(to[i],u),size[u]+=size[to[i]],mx[u]=max(mx[u],size[to[i]]); 
    	mx[u]=max(mx[u],sn-size[u]);  
    	if(mx[u]<mx[root]) root=u; 
    }  
    void calc(int u,int ff,int dep,int rt) 
    {  
    	F[rt].push_back(dep);     
    	if(Fa[rt]) G[rt].push_back(tree::Dis(Fa[rt], u));          
    	for(int i=hd[u];i;i=nex[i]) 
    		if(to[i]!=ff&&!vis[to[i]]) 
    			calc(to[i],u,dep+val[i],rt);     
    }
    void prepare(int u)
    {
    	vis[u]=1; 
    	calc(u,0,0,u);    
    	F[u].push_back(1000000004);       
    	sort(F[u].begin(),F[u].end()); 
    	if(Fa[u]) 
    	{
    		G[u].push_back(1000000004); 
    		sort(G[u].begin(),G[u].end());     
    	}
    	for(int i=hd[u];i;i=nex[i]) 
    		if(!vis[to[i]]) 
    			dfs(to[i],u),sn=size[to[i]],root=0,getroot(to[i],u),Fa[root]=u,prepare(root);     
    } 
    int query(int u,int k) 
    {   
    	int U=u, re=upper_bound(F[u].begin(),F[u].end(),k)-F[u].begin()-1;       
    	for(;Fa[u];u=Fa[u]) 
    	{
    		int dis=tree::Dis(Fa[u],U); 
    		if(dis<=k) 
    		{
    			re+=(upper_bound(F[Fa[u]].begin(),F[Fa[u]].end(),k-dis)-F[Fa[u]].begin());
    			re-=(upper_bound(G[u].begin(),G[u].end(),k-dis)-G[u].begin()); 
    		}
    	}           
    	return re;    
    }
    int main() 
    {
    	int i,j,tot=0; 
    	char ss[2]; 
    	// setIO("input"); 
    	scanf("%s%d%d",ss,&n,&K);  
    	for(i=1;i<n;++i) 
    	{
    		int a,b,c; 
    		scanf("%d%d%d",&a,&b,&c),add(a,b,c),add(b,a,c),tot+=c; 
     	} 
     	tree::dfs1(1,0);  
     	tree::dfs2(1,1); 
     	mx[0]=sn=n,root=0,getroot(1,0),prepare(root);
      	for(i=1;i<=n;++i) 
     	{
     		int l=1,r=tot,mid,ans=0; 
     		while(l<=r) 
     		{
     			mid=(l+r)>>1; 
     			if(query(i,mid)>=K) 
     			{
     				ans=mid,r=mid-1; 
     			}
     			else l=mid+1;       
     		}
     		printf("%d
    ",ans);     
     	}
    	return 0; 
    }
    

      

  • 相关阅读:
    hdu 4033Regular Polygon(二分+余弦定理)
    hdu 4405Aeroplane chess(概率DP)
    hdu 3853LOOPS (概率DP)
    网络编程基础(转)
    网络编程socket基本API详解(转)
    网络编程之socket(转)
    cf(#div1 B. Dreamoon and Sets)(数论)
    cf(#div1 A. Dreamoon and Sums)(数论)
    hdu 1805Expressions(二叉树构造的后缀表达式)
    hdu1710(Binary Tree Traversals)(二叉树遍历)
  • 原文地址:https://www.cnblogs.com/guangheli/p/11455289.html
Copyright © 2020-2023  润新知