热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[省选前题目整理][POJ1741]Tree(点分治)

题目链接http:poj.orgproblem?id1741题目大意求树上使得a到b的最短路小于等于K的无序点对(a,b)个数思路经典点分治问题。如上图,所

题目链接

http://poj.org/problem?id=1741


题目大意

求树上使得a到b的最短路小于等于K的无序点对(a,b)个数


思路

经典点分治问题。

这里写图片描述
如上图,所有符合题意的路径只可能是上面两种形态之一。我们就是要求出所有这样的长度小于等于K的路径,并去掉不合法的路径(重复经过了某条边的路径以及重复计算的路径,实际上点分治是不会出现重复计算的情况的,因为将一个树以重心分割成若干子树后,下一层分治要找的路径分别在各个子树中,不会出现重复)

首先对于当前分治的树,找出它的重心,将重心当成当前分治的树的根节点(注意此时要用一个vis数组标记重心为true,这样在DFS求DFS序、求树的重心等操作时不访问标记过的点,就能保证每次DFS时不会越出当前分治的树的范围!)
这里写图片描述

然后对这个新的树,从重心(根节点)开始进行DFS,构造出一个DFS序列,并得到每个点的深度,对这个DFS序按照每个点的深度进行升序排序
这里写图片描述

现在我们要快速地找出所有的点对(a,b),a,b是当前子树中的非根节点&#xff0c;并且depth[a]&#43;depth[b]<&#61;K

然后维护两个指针L,R&#xff0c;初始时分别指向排序后的DFS序的两端&#xff0c;表示L和所有的i属于[L&#43;1,R]&#xff0c;(L,i)是符合我们要找的点对的条件的。那么若depth[L]&#43;depth[R]<&#61;K&#xff0c;则所有的(L,i),i[L&#43;1,R]显然都是符合depth[L]&#43;depth[i]<&#61;K这一条件的&#xff0c;符合上述条件的点对个数就&#43;&#61;RL,L加1.否则说明R过大&#xff0c;R减1

但是这样做会出现一些不合法情况&#xff0c;如下图&#xff0c;以重心为根节点的子树中&#xff0c;可能出现有两个节点的LCA并不是重心&#xff0c;而是重心下的某个点&#xff0c;这样的点对之间的路径不是最短路
这里写图片描述

去掉这样的不合法情况的方法也比较简单&#xff0c;即在分治到重心下的某个儿子的子树前&#xff0c;先设这个儿子深度为重心到该儿子的边权&#xff0c;然后以该儿子为根节点DFS这个子树&#xff0c;求出DFS序并排序&#xff0c;和之前做法基本上是一样的&#xff0c;设最终在这个子树中找到的所有满足条件的点对个数为x,和之前做法相反,这次是在总答案中减去x&#xff0c;因为这些点对都是如上图形态一样的不合法的点对。


代码

#include
#include
#include
#include
#include
#include #define MAXN 10100using namespace std;int n,K,ans&#61;0;struct edge
{int u,v,w,next;
}edges[MAXN*2];int head[MAXN],nCount&#61;0;void AddEdge(int U,int V,int W)
{edges[&#43;&#43;nCount].u&#61;U;edges[nCount].v&#61;V;edges[nCount].w&#61;W;edges[nCount].next&#61;head[U];head[U]&#61;nCount;
}vector<int>seq; //dfs序列
int size[MAXN],vis[MAXN],f[MAXN],root&#61;0; //root&#61;重心,size[i]&#61;子树i大小,f[i]&#61;以i为分治的树的根的话&#xff0c;点i下面最大的儿子子树大小
int sizeOfTree; //当前分治的树的大小
int depth[MAXN];void getroot(int u,int fa)
{size[u]&#61;1;f[u]&#61;0;for(int p&#61;head[u];p!&#61;-1;p&#61;edges[p].next){int v&#61;edges[p].v;if(v&#61;&#61;fa||vis[v]) continue; //!!!!getroot(v,u);size[u]&#43;&#61;size[v];f[u]&#61;max(f[u],size[v]);}f[u]&#61;max(f[u],sizeOfTree-size[u]);if(f[u]}void getdepth(int u,int fa)
{seq.push_back(depth[u]);size[u]&#61;1;for(int p&#61;head[u];p!&#61;-1;p&#61;edges[p].next){int v&#61;edges[p].v;if(v&#61;&#61;fa||vis[v]) continue;depth[v]&#61;depth[u]&#43;edges[p].w;getdepth(v,u);size[u]&#43;&#61;size[v];}
}int cal(int u,int w) //连接到u的边边权为w,
{seq.clear();depth[u]&#61;w;getdepth(u,0);sort(seq.begin(),seq.end());int sum&#61;0;for(int l&#61;0,r&#61;seq.size()-1;lif(seq[l]&#43;seq[r]<&#61;K){sum&#43;&#61;r-l;l&#43;&#43;;}else r--;}return sum;
}void work(int u)
{ans&#43;&#61;cal(u,0);vis[u]&#61;true;for(int p&#61;head[u];p!&#61;-1;p&#61;edges[p].next){int v&#61;edges[p].v;if(!vis[v]){ans-&#61;cal(v,edges[p].w); //删去不合法的路径f[0]&#61;sizeOfTree&#61;size[v];root&#61;0; //重置树的重心getroot(v,0);work(root);}}
}int main()
{while(scanf("%d%d",&n,&K)!&#61;EOF&&!(!n&&!K)){memset(head,-1,sizeof(head));nCount&#61;0;root&#61;0;ans&#61;0;memset(vis,false,sizeof(vis));for(int i&#61;1;iint u,v,w;scanf("%d%d%d",&u,&v,&w);AddEdge(u,v,w);AddEdge(v,u,w);}f[0]&#61;sizeOfTree&#61;n; //!!!!!getroot(1,0);work(root);printf("%d\n",ans);}return 0;
}

推荐阅读
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
author-avatar
手机用户2502855967
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有