题目链接

题意

给一棵边带权树,问两点之间的距离小于等于K的点对有多少个。

思路

《分治算法在树的路径问题中的应用》

图片转载于http://www.cnblogs.com/Paul-Guderian/p/6782671.html

我对于点分治的理解:对于树上的一些问题,可以转化为答案只与当前根有关的问题,然后分治递归求解每一棵子树,统计答案。找的根应当是当前子树的重心,具体证明可以看上面的论文。

对于当前正在处理的树,这棵树的路径有两种情况:

  1. 经过根结点。

  2. 不经过根节点(在子树内)。

对于第二种情况, 我们可以递归求解转化为第一种情况来处理。于是问题变成求解第一种情况了。

这道题在cal统计答案的时候,因为我们在处理以 root 为根节点的子树的答案贡献的时候,求的是在不同子树中的距离小于等于k的点对(第一种情况),但是我们cal出来的是两种情况都包括的,因此需要减去第二种情况,即再cal一遍处理子树。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
typedef long long LL;
struct Edge {
int v, nxt, w;
} edge[N*2];
int n, k, head[N], tot, dep[N], son[N], dis[N], f[N], vis[N], sum, root, ans; void Add(int u, int v, int w) {
edge[tot] = (Edge) { v, head[u], w }; head[u] = tot++;
edge[tot] = (Edge) { u, head[v], w }; head[v] = tot++;
} void getroot(int u, int fa) { // 找重心
son[u] = 1; f[u] = 0;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if(v == fa || vis[v]) continue;
getroot(v, u);
son[u] += son[v];
f[u] = max(f[u], son[v]); // 最大的子树
}
// 当前的树中除了以u为根的树以外的结点数
// 因为当以u为根的话,除了u为根的树的结点之外的所有结点在一个子树里面
f[u] = max(f[u], sum - son[u]);
// 找一个根节点使得最大的子树最小
if(f[u] < f[root]) root = u;
} void getdeep(int u, int fa) {
// 处理出dep数组,也是当前点到根节点的距离的数组,dep[0]表示数量
dep[++dep[0]] = dis[u];
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v, w = edge[i].w;
if(vis[v] || v == fa) continue;
dis[v] = dis[u] + w;
getdeep(v, u);
}
} int cal(int u, int now) {
dep[0] = 0, dis[u] = now;
getdeep(u, 0);
sort(dep + 1, dep + 1 + dep[0]);
int res = 0, l = 1, r = dep[0];
while(l < r) {
// 对于连着l和r的两个端点,之间的所有点都可以使得距离小于等于k
if(dep[l] + dep[r] <= k) res += r - l, l++;
else r--;
} return res;
} void work(int u) {
// 计算满足dep(i)+dep(j)<=k的数目
ans += cal(u, 0);
vis[u] = 1;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v, w = edge[i].w;
if(vis[v]) continue;
// 减去满足dep(i)+dep(j)<=k并且i和j在同一个子树的数目(第二种情况)
ans -= cal(v, w);
sum = son[v];
getroot(v, root = 0); // 递归处理子树
// printf("root : %d\n", root);
work(root);
}
} int main() {
while(~scanf("%d%d", &n, &k), n + k) {
memset(head, -1, sizeof(head)); tot = 0;
memset(vis, 0, sizeof(vis));
for(int i = 1; i < n; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
Add(u, v, w);
}
sum = n, f[0] = INF, ans = 0, root = 0;
getroot(1, 0);
// printf("root : %d\n", root);
work(root);
printf("%d\n", ans);
}
return 0;
} /*
5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0
*/

POJ 1741:Tree(树上点分治)的更多相关文章

  1. POJ 1741 Tree 树上点分治

    题目链接:http://poj.org/problem?id=1741 题意: 给定一棵包含$n$个点的带边权树,求距离小于等于K的点对数量 题解: 显然,枚举所有点的子树可以获得答案,但是朴素发$O ...

  2. poj 1741 Tree(点分治)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 15548   Accepted: 5054 Description ...

  3. POJ 1741 Tree (树分治入门)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 8554   Accepted: 2545 Description ...

  4. POJ 1741 Tree (点分治)

                                                                        Tree Time Limit: 1000MS   Memory ...

  5. POJ 1741 Tree 树的分治

    原题链接:http://poj.org/problem?id=1741 题意: 给你棵树,询问有多少点对,使得这条路径上的权值和小于K 题解: 就..大约就是树的分治 代码: #include< ...

  6. POJ 1741 Tree【树分治】

    第一次接触树分治,看了论文又照挑战上抄的代码,也就理解到这个层次了.. 以后做题中再慢慢体会学习. 题目链接: http://poj.org/problem?id=1741 题意: 给定树和树边的权重 ...

  7. poj 1741 Tree (树的分治)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 30928   Accepted: 10351 Descriptio ...

  8. POJ 1741 Tree 树的分治(点分治)

    题目大意:给出一颗无根树和每条边的权值,求出树上两个点之间距离<=k的点的对数. 思路:树的点分治.利用递归和求树的重心来解决这类问题.由于满足题意的点对一共仅仅有两种: 1.在以该节点的子树中 ...

  9. POJ 1741 Tree ——(树分治)

    思路参考于:http://blog.csdn.net/yang_7_46/article/details/9966455,不再赘述. 复杂度:找树的重心然后分治复杂度为logn,每次对距离数组dep排 ...

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

                                                                                                 POJ 174 ...

随机推荐

  1. libuv和libev 异步I/O库的比较

    libuv 和 libev ,两个名字相当相近的 I/O Library,最近有幸用两个 Library 都写了一些东西,下面就来说一说我本人对两者共同与不同点的主观表述. 高性能网络编程这个话题已经 ...

  2. x:ArrayExtension

    <Window.Resources> <x:ArrayExtension x:Key="array" Type="{x:Type sys:Int32}& ...

  3. Win10《芒果TV》商店版2016-2017春节大礼,每日前100名用户免费领取7天VIP

    告别2016,喜迎2017,鸡年大吉,春节期间,每天登录Win10<芒果TV>商店版的前100位用户可领取一张芒果TV会员7天体验卡,先到先得. 芒果TV会员权益: 1.全站免广告 2.自 ...

  4. memcached对中文key的支持问题

    默认的memcached客户端对非ANSI的key存取时会有问题,有2种方式解决: 1 在get和set前将缓存的key进行UrlEncode 2 修改memcached.config文件 <e ...

  5. uwp之拍照(使用后置摄像头)

    参考:wp8.1之拍照(获取焦点,使用后置摄像头) uwp开启摄像头要借助CaptureElement呈现来自捕获设备(如照相机或网络摄像机)的流.今天讲讲如何打开摄像头,获取焦点,以及拍照.废话不多 ...

  6. 淘宝开源Key/Value结构数据存储系统Tair技术剖析

    摘要: Tair的功能 Tair是一个Key/Value结构数据的解决方案,它默认支持基于内存和文件的两种存储方式,分别和我们通常所说的缓存和持久化存储对应. Tair除了普通Key/Value系统提 ...

  7. 支付宝RSA签名之Delphi实现

    Delphi有个很大的问题就是,厂商的不作为(没有封装标准的Cipher类库),让大家自己造轮子. 今天的轮子就是RSA签名,由于Delphi没有封装Cipher类库,所以只的自己写了. 因为要在Fi ...

  8. VM中linux和windows主机进行串口通信

    最近在做关于AIS的内容.为了对AIS电文进行解码,串口收发. 数据有PC机模拟发送,为了调试方便,不用次次将程序放到开发板上运行,所以利用pc主机和虚拟机进行串口通信模拟该过程. 首先需要用到一个软 ...

  9. jqGrid使用经验分享(一)——jqGrid简单使用、json格式和jsonReader介绍

    广大的读者朋友们大家好,很高兴又可以在博客中和大家分享我的开发经验了. 此次,我准备向大家介绍一个非常好用的jQuery表格插件——jqGrid. 如果您在实际项目中遇到web端表格展示功能的需求,又 ...

  10. JVM底层实现与总结

    一.类加载器 1.BootstrapClassLoader(启动类加载器) 它主要负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定的路径以及%JAVA_HOME% ...