传送门

良心解析

其实以前在求某段序列上的区间统计问题时就碰到过类似于这样的思想。

当时的区间统计问题思路大致是这样:

选取一个点作为中间点,从这个点的左边和右边统计出满足条件的点对。然后当前的中间点就可以删去了,接着递归统计左右两个区间的方案数。

其实这就是个分治和分类讨论的思想。

满足要求的解无非就是这两种:

1.区间包含中间点(也就是两端点在中间点的左右两边)

2.区间不包含中间点(也就是两个端点都在中间点的左边或右边)

所以正确性显而易见

淀粉质就是把这种思想应用于树上的路径统计上,选取一个点作为根,然后统计经过这个点的路径数,端点一定是在子树中的,

不过这会遇到一个问题,就是两个端点会在同一颗子树中,这就需要再统计子树中的答案再减去。接着再递归求解每一颗子树。

最后一个问题就是根节点的选取,需要选重心,防止出现链导致时间复杂度退化的情况。

其次是统计答案的方法,对于此题来说有个神奇的nlogn的方法,上面的链接中已经给出。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100001
#define INF ~(1 << 31) using namespace std; int n, K, cnt, root, tot, ans;
int head[N], to[N], nex[N], val[N], f[N], size[N], deep[N], d[N];
bool vis[N];
//f[i]表示节点i的最大子树的大小
//deep[i]表示节点i到根的距离
//vis[i] == 1 表示该节点删除 inline int read()
{
int x = 0, f = 1;
char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
return x * f;
} inline void add(int x, int y, int z)
{
to[cnt] = y;
val[cnt] = z;
nex[cnt] = head[x];
head[x] = cnt++;
} //获取当前块的重心
inline void getroot(int u, int fa)
{
int i, v;
f[u] = 0;
size[u] = 1;
for(i = head[u]; ~i; i = nex[i])
{
v = to[i];
if(v == fa || vis[v]) continue;
getroot(v, u);
size[u] += size[v];
f[u] = max(f[u], size[v]);
}
f[u] = max(f[u], tot - size[u]);
if(f[u] < f[root]) root = u;
} //获取当前块中所有的点到根的距离
inline void getdeep(int u, int fa)
{
int i, v;
deep[++deep[0]] = d[u];
for(i = head[u]; ~i; i = nex[i])
{
v = to[i];
if(v == fa || vis[v]) continue;
d[v] = d[u] + val[i];
getdeep(v, u);
}
} //求解经过当前根的满足条件的路径的方案数
inline int cal(int u, int now)
{
int l, r, ret = 0;
d[u] = now;
deep[0] = 0;
getdeep(u, 0);
sort(deep + 1, deep + deep[0] + 1);
l = 1, r = deep[0];
while(l < r)
if(deep[l] + deep[r] <= K) ret += r - l++;
else r--;
return ret;
} //递归求解每一块
inline void work(int u)
{
int i, v;
vis[u] = 1;
ans += cal(u, 0);
for(i = head[u]; ~i; i = nex[i])
{
v = to[i];
if(vis[v]) continue;
//因为在求解的时候会遇到这种情况:经过当前根的满足条件的路径的两端点在同一颗子树中,这样的路径也会统计到答案中
//然而并不合法,所以需要遍历每一颗子树,减去每一颗子树中满足条件的路径
ans -= cal(v, val[i]);
tot = size[v];
root = 0;
getroot(v, u);
work(root);
}
} int main()
{
int i, x, y, z;
while(~scanf("%d %d", &n, &K))
{
if(!n && !K) break;
cnt = root = ans = 0;
memset(vis, 0, sizeof(vis));
memset(head, -1, sizeof(head));
for(i = 1; i < n; i++)
{
x = read();
y = read();
z = read();
add(x, y, z);
add(y, x, z);
}
tot = n;
f[0] = INF;
getroot(1, 0);
work(root);
printf("%d\n", ans);
}
return 0;
}

  

[POJ1741]Tree(点分治模板)的更多相关文章

  1. POJ1741 Tree 树分治模板

    http://poj.org/problem?id=1741   题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数.   dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...

  2. [poj1741]Tree(点分治+容斥原理)

    题意:求树中点对距离<=k的无序点对个数. 解题关键:树上点分治,这个分治并没有传统分治的合并过程,只是分成各个小问题,并将各个小问题的答案相加即可,也就是每层的复杂度并不在合并的过程,是在每层 ...

  3. POJ - 1741 - Tree - 点分治 模板

    POJ-1741 题意: 对于带权的一棵树,求树中距离不超过k的点的对数. 思路: 点分治的裸题. 将这棵树分成很多小的树,分治求解. #include <algorithm> #incl ...

  4. [POJ1741]Tree(点分治)

    树分治之点分治入门 所谓点分治,就是对于树针对点的分治处理 首先找出重心以保证时间复杂度 然后递归处理所有子树 对于这道题,对于点对(u,v)满足dis(u,v)<=k,分2种情况 路径过当前根 ...

  5. [bzoj1468][poj1741]Tree[点分治]

    可以说是点分治第一题,之前那道的点分治只是模模糊糊,做完这道题感觉清楚了很多,点分治可以理解为每次树的重心(这样会把数分为若干棵子树,子树大小为log级别),然后统计包含重心的整个子树的值减去各个子树 ...

  6. bzoj 1468 Tree(点分治模板)

    1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1527  Solved: 818[Submit][Status][Discuss] ...

  7. [洛谷P4178] Tree (点分治模板)

    题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...

  8. POJ1741 tree (点分治模板)

    题目大意: 给一棵有 n 个顶点的树,每条边都有一个长度(小于 1001 的正整数).定义 dist(u,v)=节点 u 和 v 之间的最小距离.给定一个整数 k,对于每一对 (u,v) 顶点当且仅当 ...

  9. POJ1741 Tree + BZOJ1468 Tree 【点分治】

    POJ1741 Tree + BZOJ1468 Tree Description Give a tree with n vertices,each edge has a length(positive ...

  10. poj1741 Tree(点分治)

    题目链接:http://poj.org/problem?id=1741 题意:求树上两点之间距离小于等于k的点对的数量 思路:点分治模板题,推荐一篇讲的非常好的博客:https://blog.csdn ...

随机推荐

  1. uvm_env——UVM大环境(UVM Environment )

    1 What is uvm_env? uvm_env is used to create and connect the uvm_components like driver, monitors , ...

  2. JS 操作内容 操作元素

    操作内容:普通元素.innerHTML = "值": 会把标记执行渲染普通元素.innerText = "值": 将值原封不动的展示出来,即使里面有标记 var ...

  3. 开源项目: circular-progress-button

    带进度条显示的按钮, 其效果如下所示: 其由三部分动画组成: 初始状态->圆环状态->完成状态. 0. 实现从初始到圆环的简单实现: 继承自button 类, 设置其背景 public c ...

  4. Robot Framework(十二) 执行测试用例——配置执行

    3.4配置执行 本节介绍可用于配置测试执行或后处理输出的不同命令行选项.与生成的输出文件相关的选项将在下一节中讨论. 3.4.1选择测试用例 通过测试套件和测试用例名称 按标签名称 当没有测试匹配选择 ...

  5. NYOJ-1057-寻找最大数(三)

    http://acm.nyist.net/JudgeOnline/problem.php?pid=1057 寻找最大数(三) 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描 ...

  6. javase(4)_数组

    一.数组概述 数组可以看成是多个相同类型数据组合,对这些数据的统一管理. 数组变量属于引用类型,数组也可以看成对象,数组中的每个元素相当于该对象的成员变量. 数组中的元素可以是任意类型,包括基本类型和 ...

  7. iOS开发遇见的坑之二:工程文件中插件和自身工程命名冲突

    在升级cocoapod后,我重新管理了一下工程,其实也就是把各个类分类进行管理 类似于这样 然后编译就发现不能运行 1.其中一个错误是工程文件缺失,根据提示添加进来进行 2.有一个是pch的相对路径变 ...

  8. jquery 获取tbody下的第二个tr 及多级标签

    <div id="testSlider"> <div class="esriTimeSlider ies-Slider" id="t ...

  9. 自写小函数处理 javascript 0.3*0.2 浮点类型相乘问题

    const reg = /^([-+]?)([0-9]+)\.([0-9]*)$/; // 判断是不是浮点数 const isFloat = function(number){ return reg. ...

  10. 【动态规划】loj#2485. 「CEOI2017」Chase

    有意思的可做dp题:细节有点多,值得多想想 题目描述 在逃亡者的面前有一个迷宫,这个迷宫由 nnn 个房间和 n−1n-1n−1 条双向走廊构成,每条走廊会链接不同的两个房间,所有的房间都可以通过走廊 ...