点分治——POJ 1741
写的第一道点分治的题目,权当认识点分治了。
点分治,就是对每条过某个点的路径进行考虑,若路径不经过此点,则可以对其子树进行考虑。
具体可以看menci的blog:点分治
来看一道例题:POJ 1741 Tree
题目大意:扔给你一颗有权无根树,求有多少条路径的长度小于k;
解题思路:先找出重心,用一次dfs处理出每个点到根的距离dis,然后将dis[]排序,用O(n)的复杂度处理出"过根且长度小于等于k的路径数目",删除根节点,对于每棵子树重复上述操作。
注意要去重:

像上面这样一个图,假设每条边的长度为1,即点到根的路径长等于点的深度,设k=4。此时dis[6]=2,dis[7]=2;dis[6]+dis[7]=4=k。但是当分治以③为根节点的子树时,dis[6]+dis[7]=2<k,这样6->7这条路径就被计算了两次,所以每次求完过根节点的符合条件的路径数之后,要减去在同一棵子树下的节点之间的符合条件的路径数。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std; struct edge{
int to,next,w;
}e[]; int root,ans,u,v,l,n,kk,ne,size;
int head[],s[],d[],dis[],f[];
//s[k]为k的子节点数目,dis[k]为k到根节点的距离
bool b[]; void add(int a,int b,int c){
e[++ne].to=b; e[ne].w=c; e[ne].next=head[a]; head[a]=ne;
} void getroot(int k,int fa){
int v,i;
s[k]=;
f[k]=;
for(i=head[k];i!=-;i=e[i].next){
v=e[i].to;
if(v!=fa&&!b[v]){
getroot(v,k);
s[k]+=s[v];//递归求子节点数目
f[k]=max(f[k],s[v]);
}
}
f[k]=max(f[k],size-s[k]);//dp求重心
if(f[k]<f[root])root=k;
} void getdis(int k,int fa){
int i,v;
d[++d[]]=dis[k];//储存距离以便排序
for(i=head[k];i!=-;i=e[i].next){
v=e[i].to;
if(v!=fa&&!b[v]){
dis[v]=dis[k]+e[i].w;//dfs求距离
getdis(v,k);
}
}
} int clac(int k,int init){
int i,j,ret=;
d[]=;
dis[k]=init;
getdis(k,);
sort(d+,d++d[]);
for(i=,j=d[];i<j;)
if(d[i]+d[j]<=kk)ret+=j-i++;//计算路径数
else j--;
return ret;
} void work(int k){
int v,i;
ans+=clac(k,);//计算路径数并加在ans上
b[k]=true;//标记重心为删除
for(i=head[k];i!=-;i=e[i].next){
v=e[i].to;
if(!b[v]){
ans-=clac(v,e[i].w);//去重
f[]=size=s[v];
getroot(v,root=);//更新重心
work(root);//对子树求解
}
}
} int main(){
int i;
while(scanf("%d%d",&n,&kk)==){
if(n==&&kk==)break;
for(i=;i<=n;i++){
head[i]=-;
b[i]=;
}
ne=;
for(i=;i<=n-;i++){
scanf("%d%d%d",&u,&v,&l);
add(u,v,l);
add(v,u,l);//注意要连双向边
}
root=;
f[]=size=n;
getroot(,);//求重心
ans=;
work(root);
printf("%d\n",ans);
}
return ;
}
总体上感觉点分治不是很难理解,只要对题目有思路应该能写出来。(orz就是写代码经常出错!b[v]写成!b[k]之类的还查不出来)
点分治——POJ 1741的更多相关文章
- 树上点分治 poj 1741
Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v ...
- 树分治 poj 1741
n k n个节点的一棵树 k是距离 求树上有几对点距离<=k; #include<stdio.h> #include<string.h> #include<algo ...
- 【POJ 1741】 Tree (树的点分治)
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...
- poj 1741 树的点分治(入门)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 18205 Accepted: 5951 Description ...
- poj 1741 Tree(树的点分治)
poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出 ...
- poj 1741 楼教主男人八题之中的一个:树分治
http://poj.org/problem? id=1741 Description Give a tree with n vertices,each edge has a length(posit ...
- POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量
POJ 1741. Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 34141 Accepted: 11420 ...
- 树的点分治 (poj 1741, 1655(树形dp))
poj 1655:http://poj.org/problem?id=1655 题意: 给无根树, 找出以一节点为根, 使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子 ...
- POJ 1741 Tree 求树上路径小于k的点对个数)
POJ 174 ...
随机推荐
- DFS判断连通图
因为是连通图,所以从任意一点出发,一定可以通过一遍深度优先遍历就能走过所有的点和边,就可以利用这个性质来很容易的通过DFS判断图是否为连通图 下面是具体算法:
- Thread--对象锁猜想
堆内存地址未发生变化: 对象堆内存地址没发生变化的情况下,即值是否与变仍然是同一把锁. 堆内存地址变化: 在线程尝试进入过同步代码时复制当前对象锁副本. 在复制对象锁副本之后改变对象指向不影响对象锁, ...
- nginx下第一次使用thinkphp5遇到的坑
最近面试php很多都在问会不会tp5所以借机了解了一下,刚在本地搭建了个就遇到了问题. 这里总结一下: 问题1.tp5+nginx=500 internal server error 我用的是phps ...
- 吴裕雄--天生自然ShellX学习笔记:Shell 输入/输出重定向
大多数 UNIX 系统命令从你的终端接受输入并将所产生的输出发送回到您的终端.一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端.同样,一个命令通常将其输出写入到标准输出,默 ...
- 第3章 ZooKeeper基本数据模型
第3章 ZooKeeper基本数据模型 3-1 zk数据模型介绍 3-2 zk客户端连接关闭服务端,查看znode ./zkCli.sh Ctrl + C 退出 =================== ...
- 02-python-运算符与表达式
目录 1. 比较运算符 2. 算数运算符 3. 赋值运算符 4. 位于运算符 5. 逻辑运算符 6. 成员运算符 7. 身份运算符 8. 运算符优先级 9. 输出输入 10. 数字类型转换及常用数学方 ...
- flask框架-下
Local与偏函数 threasing.local 多个线程修改同一个数据,复制多份变量给每个线程用,为每个线程开辟一块空间进行数据存储. 不使用therading.local # 不用local f ...
- DataStructureAndAlgorithm--第 K 个最大值
设有一组 N 个数而要确定其中第 K 个最大者,我们称之为选择问题(selection problem). 该问题的一种解法就是将这 N 个数读进一个数组中,再通过某种简单的算法,比如冒泡排序法,以递 ...
- 洛谷 P3371 【模板】单源最短路径(弱化版)(dijkstra邻接链表)
题目传送门 解题思路: 传送门 AC代码: #include<iostream> #include<cstdio> #include<cstring> using ...
- redis简单了解与简单使用
redis数据库 为什么要学习redis """ 1.redis是内存 no-sql 数据库,相比mysql等硬盘数据库效率高 2.在内存值配置数据库使用,而不直接使用内 ...