[POJ1741]Tree(点分治模板)
其实以前在求某段序列上的区间统计问题时就碰到过类似于这样的思想。
当时的区间统计问题思路大致是这样:
选取一个点作为中间点,从这个点的左边和右边统计出满足条件的点对。然后当前的中间点就可以删去了,接着递归统计左右两个区间的方案数。
其实这就是个分治和分类讨论的思想。
满足要求的解无非就是这两种:
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(点分治模板)的更多相关文章
- POJ1741 Tree 树分治模板
http://poj.org/problem?id=1741 题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数. dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...
- [poj1741]Tree(点分治+容斥原理)
题意:求树中点对距离<=k的无序点对个数. 解题关键:树上点分治,这个分治并没有传统分治的合并过程,只是分成各个小问题,并将各个小问题的答案相加即可,也就是每层的复杂度并不在合并的过程,是在每层 ...
- POJ - 1741 - Tree - 点分治 模板
POJ-1741 题意: 对于带权的一棵树,求树中距离不超过k的点的对数. 思路: 点分治的裸题. 将这棵树分成很多小的树,分治求解. #include <algorithm> #incl ...
- [POJ1741]Tree(点分治)
树分治之点分治入门 所谓点分治,就是对于树针对点的分治处理 首先找出重心以保证时间复杂度 然后递归处理所有子树 对于这道题,对于点对(u,v)满足dis(u,v)<=k,分2种情况 路径过当前根 ...
- [bzoj1468][poj1741]Tree[点分治]
可以说是点分治第一题,之前那道的点分治只是模模糊糊,做完这道题感觉清楚了很多,点分治可以理解为每次树的重心(这样会把数分为若干棵子树,子树大小为log级别),然后统计包含重心的整个子树的值减去各个子树 ...
- bzoj 1468 Tree(点分治模板)
1468: Tree Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1527 Solved: 818[Submit][Status][Discuss] ...
- [洛谷P4178] Tree (点分治模板)
题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...
- POJ1741 tree (点分治模板)
题目大意: 给一棵有 n 个顶点的树,每条边都有一个长度(小于 1001 的正整数).定义 dist(u,v)=节点 u 和 v 之间的最小距离.给定一个整数 k,对于每一对 (u,v) 顶点当且仅当 ...
- POJ1741 Tree + BZOJ1468 Tree 【点分治】
POJ1741 Tree + BZOJ1468 Tree Description Give a tree with n vertices,each edge has a length(positive ...
- poj1741 Tree(点分治)
题目链接:http://poj.org/problem?id=1741 题意:求树上两点之间距离小于等于k的点对的数量 思路:点分治模板题,推荐一篇讲的非常好的博客:https://blog.csdn ...
随机推荐
- moment.js获取当前日期是当年的第几周
/** * 实现当前日期是当年的第几周,再向前和向后推几周 * js数组保存当前日期的前后两周(共五周的数据) * */ var initSearchMajorChanges = function() ...
- python打开文件可以有多种模式
一.python打开文件可以有多种模式,读模式.写模式.追加模式,同时读写的模式等等,这里主要介绍同时进行读写的模式r+ python通过open方法打开文件 file_handler = open( ...
- 刷新本地DNS缓存的方法
http://www.cnblogs.com/rubylouvre/archive/2012/08/31/2665859.html 常有人问到域名解析了不是即时生效的嘛,怎么还是原来的呢?答案就是在本 ...
- SAP产品的Field Extensibility
SAP开发人员的工作职责,除了实现软件的功能性需求外,还会花费相当的精力实现一些非功能性需求,来满足所谓的SAP Product Standard(产品标准).这些产品标准,包含在SAP项目实施中大显 ...
- C#反射调用小DEMO
程序集的源代码: namespace DesignMode { class IOCTest { public void TestO() { Console.WriteLine("O方法&qu ...
- UVA821 PageHopping (Floyd)
求所有点直接的平均最短距离,保存一下出现过的点,题目保证是所有点连通,Floyd求出最短路以后两个for统计一下. #include<bits/stdc++.h> using namesp ...
- The - Modcrab——使用贪心策略
一.题目信息 The - Modcrab 简单翻译一下:Vova有生命值h1,每次攻击值为a1,每瓶药水恢复生命值c1;Modcrab有生命值h2,每次攻击值为a2.在每个关卡开始,Vova有两种选择 ...
- java 去掉html/style/css等标签
//定义script的正则表达式 private static String regEx_script="<script[^>]*?>[\\s\\S]*?<\\/sc ...
- linux下怎么修改mysql的字符集编码
安装完的MySQL的默认字符集为 latin1 ,为了要将其字符集改为用户所需要的(比如utf8),就必须改其相关的配置文件:由于linux下MySQL的默认安装目录分布在不同的文件下:不像windo ...
- Shell脚本中时间处理
Shell脚本中时间处理 1.脚本内容 #!/bin/bash #环境变量 #设置环境变量和sql文件格式相符 source /etc/profileexport LD_LIBRARY_PATH=&q ...