题目链接【http://poj.org/problem?id=1741】

题意:

  给出一颗树,然后寻找点对(u,v)&&dis[u][v] < k的对数。

题解:

  这是一个很经典的树分治的题。假设我们选择了一个参考点u,那么对于不同的点对(u,v),(u , v)之间的路径有两种情况,经过点u,和不经过点u,加入我算出了没有经过点u的对数,然后把经过点u的加起来就是答案了,很简单,这就是分治的思想。具体看代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1e4 + ;
int N, lit;
struct Edge
{
int to, next, len;
Edge() {}
Edge(int to, int next, int len): to(to), next(next), len(len) {}
} E[maxn * ];
int head[maxn], tot;
void initEdge()
{
for(int i = ; i <= N + ; i++) head[i] = -;
tot = ;
}
void addEdge(int u, int v, int len)
{
E[tot] = Edge(v, head[u], len);
head[u] = tot++; E[tot] = Edge(u, head[v], len);
head[v] = tot++;
}
int vis[maxn];
int dep[maxn], L, R;
int sz[maxn];
void GetSize(int u, int fa)
{
sz[u] = ;
for(int k = head[u]; ~k; k = E[k].next)
{
int v = E[k].to;
if(v == fa || vis[v]) continue;
GetSize(v, u);
sz[u] += sz[v];
}
}
void GetRoot(int u, int fa, int tot, int &rt)
{
int ma = tot - sz[u];
if(ma > tot / ) return ;
for(int k = head[u]; ~k; k = E[k].next)
{
int v = E[k].to;
if(v == fa || vis[v]) continue;
GetRoot(v, u, tot, rt);
ma = max(ma, sz[v]);
}
if(ma <= tot / ) rt = u;
}
void GetPath(int u, int fa, int len)
{
dep[R++] = len;
for(int k = head[u]; ~k; k = E[k].next)
{
int v = E[k].to;
if(v == fa || vis[v]) continue;
GetPath(v, u, len + E[k].len);
}
}
int GetNum(int L, int R)
{
int ret = ;
int pos = R - ;
sort(dep + L, dep + R);
for(int i = L; i < R; i++)
{
while(pos > i && dep[i] + dep[pos] > lit) pos--;
if(pos > i) ret += pos - i;
else break;
}
return ret;
}
int GetAns(int u)
{
int ret = , rt = ;
GetSize(u, -);
GetRoot(u, -, sz[u], rt);//找到重心
vis[rt] = ;//重心为分界点
for(int k = head[rt]; ~k; k = E[k].next)
{
int v = E[k].to;
if(vis[v]) continue;
ret += GetAns(v);//不过rt点的个数
}
L = R = ;
for(int k = head[rt]; ~k; k = E[k].next)
{
int v = E[k].to;
if(vis[v]) continue;
GetPath(v, rt, E[k].len);
ret -= GetNum(L, R);
L = R;
}
ret += GetNum(, R);
for(int i = ; i < R; i++)
if(dep[i] <= lit) ret++;
else break;
vis[rt] = ;
return ret;
}
int main ()
{
while(~scanf("%d %d", &N, &lit))
{
if(N == && lit == ) break;
initEdge();
for(int i = ; i < N; i++)
{
int u, v, len;
scanf("%d %d %d", &u, &v, &len);
addEdge(u, v, len);
}
int ans = GetAns();
printf("%d\n", ans);
}
return ;
}

POJ 1741 树分治的更多相关文章

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

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

  2. poj 1741 树的分治

    思路:这题我是看 漆子超<分治算法在树的路径问题中的应用>写的. 附代码: #include<iostream> #include<cstring> #includ ...

  3. POJ 1741 树的点分治

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

  4. POJ 1741 [点分治][树上路径问题]

    /* 不要低头,不要放弃,不要气馁,不要慌张 题意: 给一棵有n个节点的树,每条边都有一个正权值,求一共有多少个点对使得它们之间路的权值和小于给定的k. 思路: <分治算法在树的路径问题中的应用 ...

  5. [八分之三的男人] POJ - 1741 点分治 && 点分治笔记

    题意:给出一棵带边权树,询问有多少点对的距离小于等于\(k\) 本题解参考lyd的算法竞赛进阶指南,讲解的十分清晰,比网上那些讲的乱七八糟的好多了 不过写起来还是困难重重(史诗巨作 打完多校更详细做法 ...

  6. POJ 1741 点分治

    方法:指针扫描数组 每次选择树的重心作为树根,从树根出发进行一次DFS,求出点到树根的距离,把节点按照与树根的的距离放进数组d,设置两个指针L,R分别从前.后开始扫描,每次满足条件时答案累加R-L., ...

  7. POJ 1741.Tree 树分治 树形dp 树上点对

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 24258   Accepted: 8062 Description ...

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

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

  9. POJ 1741 Tree【树分治】

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

随机推荐

  1. 重构改善既有代码设计--重构手法18:Self Encapsulate Field (自封装字段)

    你直接访问一个值域(field),但与值域之间的耦合关系逐渐变得笨拙. 为这个值域建立取值/设值函数(getting/setting methods),并且只以这些函数来访问值域. private i ...

  2. [php]apache的权限解释

    格式如下: <Directory d:/...> Order allow,deny Allow from all Allow from 127.0.0.1 Deny from 110.0. ...

  3. TED_Topic3:The hidden reason for poverty the world needs to address now

    The hidden reason for poverty the world needs to address now By Gary Haugen # Background about our s ...

  4. bzoj3524/2223 [Poi2014]Couriers

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3524 http://www.lydsy.com/JudgeOnline/problem.ph ...

  5. 写一个简易浏览器、ASP.NET核心知识(3)

    前言 先在文章前面说好了,省得大家发现我根本没有这样的头发,duang的一下一堆人骂我. 这篇文章的标题有点大,其实挺low的,我需要在开头解释一下.我这里只想写一个小的控制台,旨在模拟浏览器的htt ...

  6. Linux增加swap文件

    起因 在阿里云搞了台ECS,但是内存就1个G,操作总是悲剧的卡卡卡,于是就想着增加一点交换文件来缓解一下. 快速添加交换文件 step 1. 生成文件 先填充一个大文件,等会儿当做交换文件用: dd ...

  7. c语言学习笔记.内存管理.

    内存: 每个程序的内存是分区的:堆区.栈区.静态区.代码区. 1.代码区:放置所有的可执行代码,包括main函数. 2.静态区:存放所有的全局变量和静态变量. 3.栈区:栈(stack),先进后出.存 ...

  8. layui的模块化和非模块化使用

    非模块化和模块化的区别是 非模块化不用每次都调用layui.use([],fun...)引入对应模块,引入的JS是/layui/layui.all.js 模块化必须每次都调用layui.use([], ...

  9. 【Explain】mysql之explain详解(分析索引的最佳使用)

    在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain 这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句 ...

  10. Cesium 初始化Viewer

    <pre name="code" class="javascript"><script> var viewer = new Cesium ...