传送门:http://poj.org/problem?id=1741

写的第一道树分治题,撒花纪念~

对于每一对点对(i, j),它有三种情况:

① 其中一个是根节点。这种情况比较简单,直接加上就好了。

② 横跨根节点。这种情况是重点。

③ 不是以上两种情况。这时递归下去求解就好了。

那么对于第二种情况该怎么破呢?设根节点为root,那么dist(i, root) + dist(j, root) <= k,且需要i与j在不同的子树里。直接算不同子树的点对(i, j)的个数会麻烦,所以需要一点技巧:符合条件且在不同子树的(i, j)的对数 = 符合条件的对数 - 符合条件且在相同子树的(i, j)的对数,这样就搞定啦!

#include <cstdio>
#include <cstring>
#include <algorithm> const int maxn = 10005; int n, k, t1, t2, t3, ans;
int head[maxn], to[maxn << 1], next[maxn << 1], w[maxn << 1], lb;
int siz[maxn], a[maxn], left, right;
bool book[maxn]; inline void ist(int aa, int ss, int ww) {
to[lb] = ss;
next[lb] = head[aa];
head[aa] = lb;
w[lb] = ww;
++lb;
}
int fnd_zx(int fr, int tot_node, int p, int & rt, int & mn) {
int mx = 0;
for (int j = head[fr]; j != -1; j = next[j]) {
if (!book[to[j]] && to[j] != p) {
fnd_zx(to[j], tot_node, fr, rt, mn);
mx = std::max(mx, siz[to[j]]);
}
}
mx = std::max(mx, tot_node - siz[fr]);
if (mn > mx) {
mn = mx;
rt = fr;
}
}
void get_siz(int fr, int p) {
siz[fr] = 1;
for (int j = head[fr]; j != -1; j = next[j]) {
if (!book[to[j]] && to[j] != p) {
get_siz(to[j], fr);
siz[fr] += siz[to[j]];
}
}
}
void get_data(int r, int p, int ww) {
if (ww > k) {
return;
}
a[right++] = ww;
for (int j = head[r]; j != -1; j = next[j]) {
if (!book[to[j]] && to[j] != p) {
get_data(to[j], r, ww + w[j]);
}
}
}
int get_ans(int l, int r) {
std::sort(a + l, a + r);
int rt = 0;
--r;
while (r > l) {
while (r > l && a[l] + a[r] > k) {
--r;
}
rt += r - l;
++l;
}
return rt;
}
void slove(int fr) {
int root = -666, mn = 2147483647;
get_siz(fr, 0);
fnd_zx(fr, siz[fr], 0, root, mn);
book[root] = true;
for (int j = head[root]; j != -1; j = next[j]) {
if (!book[to[j]]) {
slove(to[j]);
}
}
left = right = 0;
for (int j = head[root]; j != -1; j = next[j]) {
if (!book[to[j]]) {
get_data(to[j], root, w[j]);
ans -= get_ans(left, right);
left = right;
}
}
ans += get_ans(0, right) + right;
book[root] = false;
} int main(void) {
//freopen("in.txt", "r", stdin);
while (scanf("%d%d", &n, &k) && n && k) {
lb = 0;
memset(head, -1, sizeof head);
memset(next, -1, sizeof next);
ans = 0;
for (int i = 1; i < n; ++i) {
scanf("%d%d%d", &t1, &t2, &t3);
ist(t1, t2, t3);
ist(t2, t1, t3);
}
slove(1);
printf("%d\n", ans);
}
return 0;
}

  

最新文章

  1. C#开发微信门户及应用(22)-微信小店的开发和使用
  2. 2016年6月份那些最实用的 jQuery 插件专辑
  3. iOS开发——高级篇——流水布局UICollectionViewFlowLayout的基本使用
  4. 刨一刨内核container_of()的设计精髓
  5. iOS-设计模式-懒加载
  6. 制作支持UEFI PC的Server2008 R2系统安装U盘
  7. :“boost/serialization/string.hpp”: No such file or directory 错误
  8. android TextView加载html内容并加载图片
  9. PE结构笔记
  10. SQL Server :理解IAM 页
  11. Java使用线程池
  12. spark-RDD源码分析
  13. hp quicktestprofession ver-10.0(QTP)的入门使用指南
  14. windows php exec()不生效问题
  15. Python——Menu控件
  16. makefile 中autoload
  17. hibernate文档头的不同版本
  18. PHP安全之Web攻击(转)
  19. ReportMachine OCX 的使用方法
  20. Web安全基础实践

热门文章

  1. 关于maven的规则插件:Maven Enforcer plugin
  2. C#:excel导入导出
  3. 解决centos yum安装&quot;No package nginx available.&quot;问题
  4. Tomcat最多支持并发多少用户?
  5. Poisson distribution 泊松分布 指数分布
  6. UESTC149 解救小Q
  7. buildroot的使用简介【转】
  8. idea新建springmvc+spring+mybaties项目2
  9. Lucene dvd dvm文件便是docvalues文件——就是针对field value的列存储
  10. Masonry 比例(multipliedBy)