码迷,mamicode.com
首页 > 其他好文 > 详细

poj-1741 Tree

时间:2015-07-22 10:50:00      阅读:107      评论:0      收藏:0      [点我收藏+]

标签:poj   树的点分治   dfs   

题意:

给出一个边上带权的无根树;

求距离不大于m的结点对数;

多组数据,n<=10000;


题解:

1/8个男人留念吧。。

学了树的分治之后来切这道题,听别人讲完写写就A了;

但是发现自己模板写的好烂,改了一大通;

这题就是考虑点分治,每次在当前子树中找经过重心的点对数;

那么就是将以重心为根的距离dis数组排序,然后双指针乱扫线性找出结点对数;

但是这里可能会出现在同一子树中的情况,每个子树也做一遍减掉就可以了;

然后我在每次子树的dis数组合并的时候搞了个归并。。实测并没有全弄完之后sort好;

分治时处理每颗当前树复杂度是O(size*log size),最坏logn层,复杂度为O(nlog^2n);

我的代码跑的并不快。。329ms我尽力了。。。;


代码:


#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 11000
using namespace std;
vector<int>to[N],val[N];
int size[N],dis[N],temp[N],mi,root,bk,m,ans,cnt;
bool ban[N];
void init(int n)
{
	for(int i=1;i<=n;i++)
		to[i].clear(),val[i].clear();
	memset(ban,0,sizeof(ban));
	ans=0;
}
void get_G(int x,int pre)
{
	size[x]=1;
	int i,y,temp=0;
	for(i=0;i<to[x].size();i++)
	{
		if(!ban[y=to[x][i]]&&y!=pre)
		{
			get_G(y,x);
			size[x]+=size[y];
			temp=max(temp,size[y]);
		}
	}
	temp=max(temp,bk-temp);
	if(temp<mi)
		mi=temp,root=x;
}
void dfs(int x,int pre,int d)
{
	dis[++cnt]=d,size[x]=1;
	int i,y;
	for(i=0;i<to[x].size();i++)
	{
		if(!ban[y=to[x][i]]&&y!=pre)
		{
			dfs(y,x,d+val[x][i]);
			size[x]+=size[y];
		}
	}
}
void merge(int mid)
{
	int l=1,r=cnt,i,j,k;
	memcpy(temp+1,dis+1,sizeof(int)*cnt);
	for(i=l,j=l,k=mid+1;i<=r;i++)
	{
		if(j<=mid&&k<=r)
			dis[i]=temp[j]<temp[k]?temp[j++]:temp[k++];
		else
			dis[i]=(j==mid+1?temp[k++]:temp[j++]);
	}
}
int calc(int x)
{
	int i,j,k,y,st,ret=0;
	dis[cnt=1]=0;
	for(i=0;i<to[x].size();i++)
	{
		if(!ban[y=to[x][i]])
		{
			st=cnt+1;
			dfs(y,x,val[x][i]);
			sort(dis+st,dis+cnt+1);
			for(j=st,k=cnt;j<=cnt&&j<=k;j++)
			{
				while(dis[j]+dis[k]>m&&j<k)
					k--;
				ret+=k-j;
			}
//			merge(st-1);		//归并函数 
		}
	}
	ret=-ret;
	sort(dis+1,dis+cnt+1);		//直接排序 
	for(j=1,k=cnt;j<=cnt&&j<=k;j++)
	{
		while(dis[j]+dis[k]>m&&j<k)
			k--;
		ret+=k-j;
	}
	return ret;
}
void slove(int x)
{
	ban[x]=1;
	ans+=calc(x);
	int i,y;
	for(i=0;i<to[x].size();i++)
	{
		if(!ban[y=to[x][i]])
		{
			mi=0x3f3f3f3f,bk=size[y];
			get_G(y,x);
			slove(root);
		}
	}
}
int main()
{
	int n,i,j,k,x,y,v;
	while(scanf("%d%d",&n,&m)&&(n||m))
	{
		init(n);
		for(i=1;i<n;i++)
		{
			scanf("%d%d%d",&x,&y,&v);
			to[x].push_back(y),val[x].push_back(v);
			to[y].push_back(x),val[y].push_back(v);
		}
		mi=0x3f3f3f3f,bk=n;
		get_G(1,0);
		slove(root);
		printf("%d\n",ans);
	}
	return 0;
}



poj-1741 Tree

标签:poj   树的点分治   dfs   

原文地址:http://blog.csdn.net/ww140142/article/details/46998089

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!