POJ1741&&BZOJ1468 男人八题

去年这个时候就做这道题了  那个时候完全不懂 

今天重新来学了一下点分治  发现自己很多不会


没有照着别人的程序打点分治的时候思路很乱   可能是自己太弱了

后来看了黄学长的代码发现有些东西我打的太复杂了。。。。

然后我就像到了一个新世界


每次都去找中心就好了。。。。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;


char c;
bool flag;
inline void read(int &a)
{
	a=0,flag=false;do c=getchar();while(c!='-'&&(c<'0'||c>'9'));
	if(c=='-')flag=true,c=getchar();
	while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
   if(flag)a=-a;
}
int root;
struct Chain{Chain *next;int u,len;Chain(){next=NULL;}}*Head[100001];
bool choose[10001];
int sum;
int Max[100001],son[100001];
void Get_Root(int u,int fa)
{
	son[u]=1;
	Max[u]=0;
	for(Chain *tp=Head[u];tp;tp=tp->next)
	{
		if(tp->u==fa||choose[tp->u])continue;
		Get_Root(tp->u,u);
		son[u]+=son[tp->u];
		Max[u]=max(Max[u],son[tp->u]);
	}
	Max[u]=max(Max[u],sum-son[u]);
	if(Max[u]<Max[root])root=u;
}
int deep[100001];
inline void addside(int a,int b,int len)
{	Chain *tp=new Chain;
	tp->u=b,tp->len=len,tp->next=Head[a];
	Head[a]=tp;
	swap(a,b);
    tp=new Chain;
	tp->u=b,tp->len=len,tp->next=Head[a];
	Head[a]=tp;
}
int D[100001];
inline void De(int u,int fa)
{
	for(Chain *tp=Head[u];tp;tp=tp->next)
        if(tp->u!=fa&&!choose[tp->u])
           D[tp->u]=D[u]+tp->len,deep[++deep[0]]=D[tp->u],De(tp->u,u);
}
int k;
int Sol_dep(int u,int delta)
{
	int res=0;
       deep[0]=0;
	   D[u]=deep[++deep[0]]=delta;
	   De(u,u);
       sort(deep+1,deep[0]+deep+1);
       int l=1,r=deep[0];
       while(l<r)
       {
       
	     if(deep[l]+deep[r]>k) 	 
			   r--;
	      else res+=r-l,l++;
	   }
	   return res;
}
int ans;
int Div(int u)
{
	ans+=Sol_dep(u,0);
	choose[u]=true;
	for(Chain *tp=Head[u];tp;tp=tp->next)
	  {
	  	  if(choose[tp->u])continue;
	  	  ans-=Sol_dep(tp->u,tp->len);
	  	  sum=son[tp->u];
	  	  root=0;
	  	  Get_Root(tp->u,root);
	  	  Div(root);
	  }
}

int main()
{ 
int a,b,c;
while(true)
{
	int n;
	read(n),read(k);
	memset(choose,false,sizeof(choose));
	if(!n)return 0;
	for(int i=1;i<=n;i++)
	  Head[i]=NULL;
	for(int i=1;i<n;i++)
	   {
	   	read(a),read(b),read(c),addside(a,b,c);
	   }
	sum=n;root=0;
	Max[0]=1<<29;
	ans=0;
	Get_Root(1,0);
	Div(root);
	printf("%d\n",ans);
}
	
	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值