[POJ1741] Tree【树分治 点分治】
2024-09-03 20:49:13
传送门: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;
}
最新文章
- C#开发微信门户及应用(22)-微信小店的开发和使用
- 2016年6月份那些最实用的 jQuery 插件专辑
- iOS开发——高级篇——流水布局UICollectionViewFlowLayout的基本使用
- 刨一刨内核container_of()的设计精髓
- iOS-设计模式-懒加载
- 制作支持UEFI PC的Server2008 R2系统安装U盘
- :“boost/serialization/string.hpp”: No such file or directory 错误
- android TextView加载html内容并加载图片
- PE结构笔记
- SQL Server :理解IAM 页
- Java使用线程池
- spark-RDD源码分析
- hp quicktestprofession ver-10.0(QTP)的入门使用指南
- windows php exec()不生效问题
- Python——Menu控件
- makefile 中autoload
- hibernate文档头的不同版本
- PHP安全之Web攻击(转)
- ReportMachine OCX 的使用方法
- Web安全基础实践
热门文章
- 关于maven的规则插件:Maven Enforcer plugin
- C#:excel导入导出
- 解决centos yum安装";No package nginx available.";问题
- Tomcat最多支持并发多少用户?
- Poisson distribution 泊松分布 指数分布
- UESTC149 解救小Q
- buildroot的使用简介【转】
- idea新建springmvc+spring+mybaties项目2
- Lucene dvd dvm文件便是docvalues文件——就是针对field value的列存储
- Masonry 比例(multipliedBy)