POJ1741 Tree(树的点分治)
2016-03-01 09:58
411 查看
题目给一棵边带权的树,统计路径长度<=k的点对数。
楼教主男人八题之一,分治算法在树上的应用。
一开始看论文看不懂,以为重心和距离那些是一遍预处理得来的。。感觉上不敢想每棵子树都求一遍重心和距离——那样时间复杂度怎么会只有O(nlogn)?
后来想通了,真的是对于每颗子树都把其所有结点单独提取出来,而且这么做就是O(nlogn)!
首先每次都选择重心进行分治,这样最多大概处理logn层,每一层都包含若干棵子树;
考虑每一层的每棵子树要提取的结点个数的和:第一层:n,第二层:n-1(第一层子树个数),第三层:n-(第一层子树个数+第二层子树个数)……不妨就认为每一层都有n个结点的信息要处理,而有logn层,所以其实总共就只有nlogn个(次)结点要处理;
对于每一层每棵子树求重心的时间复杂度是线性的,而每层n个结点,最多logn层,所以求重心时间的复杂度就是O(nlogn);
对于这道题子树要计算的信息是各个结点到根的距离,然后对其排序并在线性时间复杂度统计点对数目,其处理每棵子树时间复杂度是O(xlogx),x为该子树结点个数;不妨设某层各个子树结点个数为a、b、c……,而a+b+c+……=n,则aloga+blogb+clogc<=nlogn,共logn层,所以处理所有层所有子树信息的时间复杂度就是O(nlog2n);
故这一题用点分治的时间复杂度是O(nlog2n)!
写这一题,捋清思路后分了好几个函数逐一实现,感觉框架挺清晰的,提交之后就1A还是很爽的。
楼教主男人八题之一,分治算法在树上的应用。
一开始看论文看不懂,以为重心和距离那些是一遍预处理得来的。。感觉上不敢想每棵子树都求一遍重心和距离——那样时间复杂度怎么会只有O(nlogn)?
后来想通了,真的是对于每颗子树都把其所有结点单独提取出来,而且这么做就是O(nlogn)!
首先每次都选择重心进行分治,这样最多大概处理logn层,每一层都包含若干棵子树;
考虑每一层的每棵子树要提取的结点个数的和:第一层:n,第二层:n-1(第一层子树个数),第三层:n-(第一层子树个数+第二层子树个数)……不妨就认为每一层都有n个结点的信息要处理,而有logn层,所以其实总共就只有nlogn个(次)结点要处理;
对于每一层每棵子树求重心的时间复杂度是线性的,而每层n个结点,最多logn层,所以求重心时间的复杂度就是O(nlogn);
对于这道题子树要计算的信息是各个结点到根的距离,然后对其排序并在线性时间复杂度统计点对数目,其处理每棵子树时间复杂度是O(xlogx),x为该子树结点个数;不妨设某层各个子树结点个数为a、b、c……,而a+b+c+……=n,则aloga+blogb+clogc<=nlogn,共logn层,所以处理所有层所有子树信息的时间复杂度就是O(nlog2n);
故这一题用点分治的时间复杂度是O(nlog2n)!
写这一题,捋清思路后分了好几个函数逐一实现,感觉框架挺清晰的,提交之后就1A还是很爽的。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define INF (1<<30) #define MAXN 11111 struct Edge{ int v,w,next; }edge[MAXN<<1]; int NE,head[MAXN]; void addEdge(int u,int v,int w){ edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u]; head[u]=NE++; } int n,k,ans; bool vis[MAXN]; int centre,minimum,size[MAXN]; void getSize(int u,int fa){ size[u]=1; for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(v==fa || vis[v]) continue; getSize(v,u); size[u]+=size[v]; } } void getCentre(int u,int fa,int &tot){ int res=tot-size[u]; for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(v==fa || vis[v]) continue; res=max(res,size[v]); getCentre(v,u,tot); } if(minimum>res){ minimum=res; centre=u; } } int a[MAXN],b[MAXN],an,bn; void dfs(int u,int fa,int dist){ a[an++]=b[bn++]=dist; for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(v==fa || vis[v]) continue; dfs(v,u,dist+edge[i].w); } } int count(int *c,int &cn){ sort(c,c+cn); int res=0,i=0,j=cn-1; while(i<j){ while(i<j && c[i]+c[j]>k) --j; res+=j-i; ++i; } return res; } void conquer(int u){ an=0; a[an++]=0; for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(vis[v]) continue; bn=0; dfs(v,u,edge[i].w); ans-=count(b,bn); } ans+=count(a,an); } void divide(int u){ getSize(u,u); minimum=INF; getCentre(u,u,size[u]); u=centre; vis[u]=1; conquer(u); for(int i=head[u]; i!=-1; i=edge[i].next){ int v=edge[i].v; if(vis[v]) continue; divide(v); } } int main(){ int a,b,c; while(scanf("%d%d",&n,&k),(n||k)){ NE=0; memset(head,-1,sizeof(head)); for(int i=1; i<n; ++i){ scanf("%d%d%d",&a,&b,&c); addEdge(a,b,c); addEdge(b,a,c); } ans=0; memset(vis,0,sizeof(vis)); divide(1); printf("%d\n",ans); } return 0; }
相关文章推荐
- BW标准数据源初始化设置
- iOS tabBar去掉黑线
- iOS9 beta 请求出现App Transport Security has blocked a cleartext HTTP (http://)
- PAT : 1048. 数字加密(20)
- 45个非常有用的查询语句
- Android ViewPager实现无限循环效果
- JQuery Mobile入门——页面缓存
- Codeforces Round #343 (Div. 2)【A,B水题】
- Codeforces Round #343 (Div. 2)【A,B水题】
- Java中数组和List集合如何互相转换
- 【深圳信狮】安卓技术更新有哪些?
- Android开源项目—图表开源项目MPAndroidChart
- ns3官网文档图例的理解
- 《基于MFC的OpenGL编程》Part 7 Colors
- 关于百度地图bug之一——infowindow重影问题
- Java 中新增的 foreach 的用法
- ADO连接ACCESS2007及以上版本的数据库
- 一个链式二叉搜索树接口(为下一篇红黑树的内容做铺垫)
- tomcat启动为什么 写入这句话 -Dspring.profiles.active=dev
- 【c#学习笔记】 基础篇