poj 1741Tree(点分治)
发布日期:2021-11-12 00:25:43
浏览次数:3
分类:技术文章
本文共 3021 字,大约阅读时间需要 10 分钟。
Tree
Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. Write a program that will count how many pairs which are valid for a given tree. Input The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l. The last test case is followed by two zeros. Output For each test case output the answer on a single line. Sample Input 5 41 2 31 3 11 4 23 5 10 0 Sample Output 8 Source |
论文题:
题意:
题解
参考博客:
每次分治,我们首先算出重心,为了计算重心,需要进行两次dfs,第一次把以每个结点为根的子树大小求出来,第二次是从这些结点中找重心
找到重心后,需要统计所有结点到重心的距离,看其中有多少对小于等于K,这里采用的方法就是把所有的距离存在一个数组里,进行快速排序,这是nlogn的,然后用一个经典的相向搜索O(n)时间内解决。但是这些求出来满足小于等于K的里面只有那些路径经过重心的点对才是有效的,也就是说在同一颗子树上的肯定不算数的,所以对每颗子树,把子树内部的满足条件的点对减去。
最后的复杂度是n logn logn 其中每次快排是nlogn 而递归的深度为logn
注意这里求重心和以往不同,因为每次分治都要对一棵子树求重心,所以这棵树的大小不定,所以要两次dfs。详细操作见代码。
#include#include #include #include #include #include #include using namespace std;#define rep(i,a,n) for (int i=a;i =a;i--)#define pb push_back#define fi first#define se secondtypedef vector VI;typedef long long ll;typedef pair PII;const int inf=0x3fffffff;const ll mod=1000000007;const int maxn=10000+100;int head[maxn],vis[maxn],dis[maxn];struct edge{ int to,next,w;}e[maxn*2]; //int tol=0;void add(int u,int v,int w){ e[++tol].to=v,e[tol].next=head[u],e[tol].w=w,head[u]=tol;}int root,mi,num;int mx[maxn];int ans=0;int n,k;int tn;int sz[maxn];void dfssize(int u,int f) //处理子树大小{ sz[u]=1;mx[u]=0; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(v==f||vis[v]) continue; dfssize(v,u); sz[u]+=sz[v]; if(sz[v]>mx[u]) mx[u]=sz[u]; }}void dfsroot(int r,int u,int f) //求重心{ if(sz[r]-sz[u]>mx[u]) mx[u]=sz[r]-sz[u]; if(mi>mx[u]) { mi=mx[u]; root=u; } for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(vis[v]||v==f) continue; dfsroot(r,v,u); }}void getdis(int u,int f,int d)//求距离{ dis[num++]=d; for(int i=head[u];i;i=e[i].next) { int v=e[i].to; if(vis[v]||v==f) continue; getdis(v,u,d+e[i].w); }}int cal(int u,int d){ int res=0; num=0; getdis(u,-1,d); sort(dis,dis+num); int i=0,j=num-1; while(i k) j--; res+=j-i; i++; } return res;}void dfs(int u){ mi=inf; dfssize(u,-1); //这一步和下面的一步求出重心 dfsroot(u,u,-1); ans+=cal(root,0); vis[root]=1; //将这个根处理完后打上标记“去掉” for(int i=head[root];i;i=e[i].next) { int v=e[i].to; if(vis[v]) continue; ans-=cal(v,e[i].w); dfs(v); }}int main(){ while(~scanf("%d%d",&n,&k)) { if(n==0&&k==0) break; tol=0;ans=0; memset(head,0,sizeof(head)); memset(sz,0,sizeof(sz)); memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); rep(i,1,n) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w),add(v,u,w); } dfs(1); printf("%d\n",ans); } return 0;}
转载地址:https://blog.csdn.net/fouzhe/article/details/55258714 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
做的很好,不错不错
[***.243.131.199]2024年04月17日 04时29分05秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
SQL Server 存储过程的分页方案比拼
2021-06-30
不需xp_cmdshell支持在有注入漏洞的SQL服务器上运行CMD命令
2021-06-30
SQLserver安全设置攻略
2021-06-30
Sql server 2005带来的分页便利
2021-06-30
修改SQL SERVER内置存储过程
2021-06-30
如何将SQL Server表驻留内存和检测
2021-06-30
打印自定义纸张大小
2021-06-30
C#字符串处理类
2021-06-30
C#索引器
2021-06-30
c#事件
2021-06-30
网页刷新方法集合
2021-06-30
在SecureCRT下使用sz下载和rz上传文件
2021-06-30
在ASP.NET 2.0中使用样式、主题和皮肤
2021-06-30
图片、文件防盗链
2021-06-30
ASP.Net 2.0 发送邮件的代码
2021-06-30
Linux动态库和静态库比较
2021-06-30
c#中什么情况下用(int)什么情况下用Convert.ToInt32
2021-06-30
ASP.Net中利用CSS实现多界面两法
2021-06-30
PHP更新数据库记录
2021-06-30
C#调用windows api的要点
2021-06-30