传送门

良心解析

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

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

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

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

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

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. web前端性能优化 (share)

    本文转自:http://www.cnblogs.com/50614090/archive/2011/08/19/2145620.html 一. WEB前台的优化规则 一.尽量减少 HTTP 请求 有几 ...

  2. 【Web应用-大文件部署】上传超过 2M 的文件到 Azure PHP 网站失败

    问题描述 上传超过 2M 的文件到 Azure PHP 网站失败. 问题分析 由于 PHP 本身默认上传文件的上限是 2M,所以当上传超过2M的文件时会报错. 解决方法 根据以下步骤进行配置: 在 s ...

  3. jni log 使用

    1. 在源文件中添加头文件 #include <android/log.h> #define LOG_TAG "System.out.c" #define LOGD(. ...

  4. WPF使用附加属性绑定,解决data grid列绑定不上的问题

    背景 需要对datagrid的列header添加自定义属性,然后绑定,并根据不同的列header绑定不同的值,传统的加扩展类太麻烦,而附加属性的特点更适用于这种场景. 1.xaml 代码 <Da ...

  5. java数字金额转化为中文金额

    public static String digitUppercase(double n){String fraction[] = {"角", "分"};Str ...

  6. iOS 常用尺寸

    APP ICON: @1x:57*57 @2x:114*114 @3x:171*171  机型 屏幕尺寸   像素(px)pixel  点(pt)point    PPI iphone4s 3.5吋  ...

  7. iOS开发遇到的坑之三--使用asi框架在xcode下正常运行,但是打包时却不能进行网络访问

    前言: 前两篇博客遇到的问题是前几天在实验室开发的时候遇到的,花了两三天时间在上面,今天突然心血来潮,想把这些”坑”写下来,所以才有了这两篇写的很丑的博客随笔 今天在开发时又遇到一个问题,那就是标题所 ...

  8. 使用custom elements和Shadow DOM自定义标签

    具体的api我就不写 官网上面多  如果不知道这个的话也可以搜索一下 目前感觉这个还是相当好用的直接上码. <!DOCTYPE html> <html lang="en&q ...

  9. tkinter学习-文本框

    阅读目录 Entry 输入框 Text 文本框 Entry: 说明:输入控件,用于显示简单的文本内容 属性:在输入框中用代码添加和删除内容,同样也是用insert()和delete()方法 from ...

  10. RN踩坑

    使用夜神 使用夜神作为模拟器,这个模拟器启动就会监听62001端口. 开发工具与模拟器的通信都是通过adb.夜神模拟器的安装目录/bin下有一个adb.exe,android sdk tools下也有 ...