写的第一道点分治的题目,权当认识点分治了。

点分治,就是对每条过某个点的路径进行考虑,若路径不经过此点,则可以对其子树进行考虑。

具体可以看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的更多相关文章

  1. 树上点分治 poj 1741

    Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v ...

  2. 树分治 poj 1741

    n k n个节点的一棵树 k是距离 求树上有几对点距离<=k; #include<stdio.h> #include<string.h> #include<algo ...

  3. 【POJ 1741】 Tree (树的点分治)

    Tree   Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...

  4. poj 1741 树的点分治(入门)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 18205   Accepted: 5951 Description ...

  5. poj 1741 Tree(树的点分治)

    poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出 ...

  6. poj 1741 楼教主男人八题之中的一个:树分治

    http://poj.org/problem? id=1741 Description Give a tree with n vertices,each edge has a length(posit ...

  7. POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量

    POJ 1741. Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 34141   Accepted: 11420 ...

  8. 树的点分治 (poj 1741, 1655(树形dp))

    poj 1655:http://poj.org/problem?id=1655 题意: 给无根树,  找出以一节点为根,  使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子 ...

  9. POJ 1741 Tree 求树上路径小于k的点对个数)

                                                                                                 POJ 174 ...

随机推荐

  1. python刷LeetCode:5. 最长回文子串

    难度等级:中等 题目描述: 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad"输出: "bab& ...

  2. hadoop cmd

    一.hadoop文件操作 1.Ls hadoop fs -ls / 2.Put hadoop fs -put xx /path 3.Mkdir hadoop fs -mkdir 4.要从HDFS中删除 ...

  3. Linux(CENTOS7) Redis安装

    1.下载redis         在disk目录下,输入以下命令进行下载: wget http://download.redis.io/releases/redis-2.8.3.tar.gz 2.解 ...

  4. 剑指offer【08】- 二叉树的深度(java)

    题目:二叉树的深度 考点:知识迁移能力 题目描述:输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 牛客网上的剑指offer题, ...

  5. 今天 运营同事发现的bug记录 上传商品时商品名称带双引号 导致输出页面时 双引号被转义

    例如  ”sk||““美白”淡化 这样输出表单页面时显示出来的只有sk||  解决办法 把输出文字对双引号进行转义

  6. bugs开发异常解决方法

    1.      前提 第一层:遇到异常首先必须告诉自己,冷静,不要慌.(一看到Bug就心慌,那么就不能释放必杀技) 2.      入门级 第二层:遇到Bug,第一潜意识看输出异常的信息的(控制台输出 ...

  7. iTOP-4412-Ubuntu系统源码-ubuntu没有声音的解决办法

    准备工作 1.下载 vim 在命令行上输入 apt-get install vim 下载 vim 2.输入 vim /etc/hosts 在所打开界面的第一行最后写上 iTOP4412-ubuntu- ...

  8. 吴裕雄--天生自然Linux操作系统:Linux 系统启动过程

    linux启动时我们会看到许多启动信息. Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导. 运行 init. 系统初始化. 建立终端 . 用户登录系统. in ...

  9. Java web之jsp,xml(2020.1.7)

    1.xml文档规则 xml声明 字符集 xml元素的基本规则: 合法标签名 嵌套子元素 空元素

  10. MySql 相关面试题

    1.mysql 慢查询 目的:通过慢查询日志,记录超过指定时间的 SQL 语句,优化 sql 查询 步骤:查看慢查询开启状态-->设置慢查询 http://www.cnblogs.com/luy ...