树上的算法真的很有意思……哈哈。

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

将无根树转化成有根树进行观察。满足条件的点对有两种情况:两个点的路径横跨树根,两个点位于同一颗子树中。

如果我们已经知道了此时所有点到根的距离a[i],a[x] + a[y] <= k的(x, y)对数就是结果,这个可以通过排序之后O(n)的复杂度求出。然后根据分治的思想,分别对所有的儿子求一遍即可,但是这会出现重复的——当前情况下两个点位于一颗子树中,那么应该将其减掉(显然这两个点是满足题意的,为什么减掉呢?因为在对子树进行求解的时候,会重新计算)。

在进行分治时,为了避免树退化成一条链而导致时间复杂度变为O(N^2),每次都找树的重心,这样,所有的子树规模就会变的很小了。时间复杂度O(Nlog^2N)。

树的重心的算法可以线性求解。

#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
#define N 10009
struct node {
int v, l;
node() {};
node(int _v, int _l): v(_v), l(_l) {};
};
vector<node> g[N];
int n, k, size, s[N], f[N], root, d[N], K, ans;
vector<int> dep;
bool done[N];
void getroot(int now, int fa) {
int u;
s[now] = 1; f[now] = 0;
for (int i=0; i<g[now].size(); i++)
if ((u = g[now][i].v) != fa && !done[u]) {
getroot(u, now);
s[now] += s[u];
f[now] = max(f[now], s[u]);
}
f[now] = max(f[now], size-s[now]);
if (f[now] < f[root]) root = now;
}
void getdep(int now, int fa) {
int u;
dep.push_back(d[now]);
s[now] = 1;
for (int i=0; i<g[now].size(); i++)
if ((u = g[now][i].v) != fa && !done[u]) {
d[u] = d[now] + g[now][i].l;
getdep(u, now);
s[now] += s[u];
}
}
int calc(int now, int init) {
dep.clear(); d[now] = init;
getdep(now, 0);
sort(dep.begin(), dep.end());
int ret = 0;
for (int l=0, r=dep.size()-1; l<r; )
if (dep[l] + dep[r] <= K) ret += r-l++;
else r--;
return ret;
}
void work(int now) {
int u;
ans += calc(now, 0);
done[now] = true;
for (int i=0; i<g[now].size(); i++)
if (!done[u = g[now][i].v]) {
ans -= calc(u, g[now][i].l);
f[0] = size = s[u];
getroot(u, root=0);
work(root);
}
}
int main() { while (scanf("%d%d", &n, &K) == 2) {
if (n == 0 && K == 0) break;
for (int i=0; i<=n; i++) g[i].clear();
memset(done, false, sizeof(done)); int u, v, l;
for (int i=1; i<n; i++) {
scanf("%d%d%d", &u, &v, &l);
g[u].push_back(node(v, l));
g[v].push_back(node(u, l));
}
f[0] = size = n;
getroot(1, root=0);
ans = 0;
work(root);
printf("%d\n", ans);
}
return 0;
}

POJ 1741 Tree【Tree,点分治】的更多相关文章

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

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

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

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

  3. POJ 1741:Tree(树上点分治)

    题目链接 题意 给一棵边带权树,问两点之间的距离小于等于K的点对有多少个. 思路 <分治算法在树的路径问题中的应用> 图片转载于http://www.cnblogs.com/Paul-Gu ...

  4. 【POJ 1741】Tree

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 11570   Accepted: 3626 Description ...

  5. 「POJ 1741」Tree

    题面: Tree Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define ...

  6. 【POJ 1741】 Tree

    [题目链接] http://poj.org/problem?id=1741 [算法] 点分治 要求距离不超过k的点对个数,不妨将路径分成两类 : 1. 经过根节点 2. 不经过根节点 考虑第1类路径, ...

  7. POJ 1741 树的点分治

    题目大意: 树上找到有多少条路径的边权值和>=k 这里在树上进行点分治,需要找到重心保证自己的不会出现过于长的链来降低复杂度 #include <cstdio> #include & ...

  8. POJ 1741 树上的点分治

    题目大意: 找到树上点对间距离不大于K的点对数 这是一道简单的练习点分治的题,注意的是为了防止点分治时出现最后分治出来一颗子树为一条直线,所以用递归的方法求出最合适的root点 #include &l ...

  9. POJ 1741 树上 点的 分治

    题意就是求树上距离小于等于K的点对有多少个 n2的算法肯定不行,因为1W个点 这就需要分治.可以看09年漆子超的论文 本题用到的是关于点的分治. 一个重要的问题是,为了防止退化,所以每次都要找到树的重 ...

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

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

随机推荐

  1. NGUI Button 3中点击事件的触发

    NGUI事件的种类很多,比如点击.双击.拖动.滑动等等,他们处理事件的原理几乎万全一样,本文只用按钮来举例. 1.直接监听事件 把下面脚本直接绑定在按钮上,点击按钮触发的方法名必须为OnClick,当 ...

  2. Visual Studio的ASP.NET修改默认打开浏览器

    1.新建web空应用程序,输入项目名称. 2.右击项目名称,添加“新建项”—一般处理程序 3.右击新建一个HTML文件,任意命名. 4.右击新建的Html文件,选择“浏览方式” 5.选择后弹出浏览器选 ...

  3. 5.4.2 RegExp实例方法

    RegExp对象的主要方法是exec(),该方法是专门为辅助组而设计的.exec()接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组:或者在没有匹配项的情况下返回null.返回的 ...

  4. LintCode-子数组之和

    题目描述: 给定一个整数数组,找到和为零的子数组.你的代码应该返回满足要求的子数组的起始位置和结束位置 样例 给出 [-3, 1, 2, -3, 4],返回[0, 2] 或者 [1, 3]. publ ...

  5. ie6与固定定位fixed,+ 条件注释格式注意

    ie6并不支持position:fixed, ie7+都支持fixed定位, ie6固定定位实现方法1: <!DOCTYPE html> <html> <head> ...

  6. python2.6升级到2.7

    开发部需要使用python2.7,由于公网的环境python版本都是系统自带的,版本是2.6,需要升级,最好是通过RPM升级. Linux系统:CentOS CentOS 6.4升级Python后yu ...

  7. Linux批量重命名文件

    五种方法实现Linux批量重命名文件 Linux批量重命名文件是指对某些特定的文件统一进行重新命名,以改变原来一批文件的名称,这里介绍五种方法来实现. Linux批量重命名文件会涉及到改变一个字母.改 ...

  8. Windows Azure HDInsight 支持预览版 Hadoop 2.2 群集

     Windows Azure HDInsight 支持预览版 Hadoop 2.2 群集 继去年 10 月推出 Windows Azure HDInsight 之后,我们宣布 Windows Az ...

  9. MFC自绘控件学习总结

    前言:从这学期开始就一直在学习自绘控件(mfc),目标是做出一款播放器界面,主要是为了打好基础,因为我基础实在是很烂....说说我自己心得体会以及自绘控件的方法吧,算是吐槽吧,说的不对和不全的地方,或 ...

  10. BZOJ 2463 谁能赢呢? (博弈论)

    题解:简单博弈论 #include <cstdio> int main(){ int n; while(scanf("%d",&n),n!=0) if (n&a ...