普通dfs访问每个点对的复杂度是O(n^2)的,显然会超时。

考虑访问到当前子树的根节点时,统计所有经过根的点(u, v)满足:

dist(u) + dist(v) <= maxd,并且

belong(u)≠belong(v)(即u,v不在同一子树)。

这里说的距离指的是节点到跟的距离。

可以用作差法,即用所有满足条件的点对数减去那些在根节点为当前子树根节点的儿子节点的点对数。

上面一步可以用O(nlogn)的复杂度解决,即先排序再比较。

根节点子树可以递归解决,用树的点分治。

总复杂度上界是O(nlognlogn)。

http://poj.org/problem?id=1987

 #include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + ;
const int inf = 0x3f3f3f3f;
struct Edge{
int to, next, w;
}edge[maxn << ];
int head[maxn], N;
int n, m, maxd;
bool vis[maxn];
int cnt[maxn];
int maxi[maxn];
int ans;
int mini, root, sum;
int buf[maxn], k; void addEdge(int u, int v, int w){
edge[N].next = head[u];
edge[N].to = v;
edge[N].w = w;
head[u] = N++;
} void init(){
N = ;
memset(head, -, sizeof head);
} void get_cnt(int u){
cnt[u] = ;
vis[u] = ;
maxi[u] = -;
buf[k++] = u;
for(int i = head[u]; i + ; i = edge[i].next){
int v = edge[i].to;
if(vis[v]) continue;
get_cnt(v);
cnt[u] += cnt[v];
maxi[u] = max(maxi[u], cnt[v]);
}
vis[u] = ;
} void get_dist(int u, int d){
vis[u] = ;
buf[k++] = d;
for(int i = head[u]; i + ; i = edge[i].next){
int v = edge[i].to;
if(vis[v]) continue;
get_dist(v, d + edge[i].w);
}
vis[u] = ;
} int get_buf_sum(int left, int right){
sort(buf + left, buf + right);
int tem = ;
for(int i = right - , j = left; i >= left + ; i--){
while(j < i && buf[i] + buf[j] <= maxd) ++j;
tem += min(i, j) - left;
}
return tem;
} void cal(int u){
k = ;
get_cnt(u);
mini = inf;
for(int i = ; i < k; i++){
int tem = max(cnt[u] - cnt[buf[i]], maxi[buf[i]]);
if(tem < mini) mini = tem, root = buf[i];
}
k = ;
vis[root] = ;
int tem = ;
for(int i = head[root]; i + ; i = edge[i].next){
int v = edge[i].to;
if(vis[v]) continue;
int pre = k;
get_dist(v, edge[i].w);
tem -= get_buf_sum(pre, k);
}
buf[k++] = ;
tem += get_buf_sum(, k);
ans += tem;
for(int i = head[root]; i + ; i = edge[i].next){
int v = edge[i].to;
if(vis[v]) continue;
cal(v);
}
} void solve(){
scanf("%d", &maxd);
memset(vis, , sizeof vis);
ans = ;
for(int i = ; i <= n; i++){
if(!vis[i]) cal(i);
}
printf("%d\n", ans);
} int main(){
//freopen("in.txt", "r", stdin);
while(~scanf("%d", &n)){
scanf("%d", &m);
init();
for(int i = , x, y, z; i < m; i++){
scanf("%d%d%d", &x, &y, &z);
addEdge(x, y, z);
addEdge(y, x, z);
getchar(), getchar();
}
solve();
}
return ;
}

poj1987 Distance Statistics的更多相关文章

  1. 【点分治】poj1741 Tree / poj2114 Boatherds / poj1987 Distance Statistics

    三道题都很类似.给出1741的代码 #include<cstdio> #include<algorithm> #include<cstring> using nam ...

  2. POJ 1987 Distance Statistics 树分治

    Distance Statistics     Description Frustrated at the number of distance queries required to find a ...

  3. BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治

    BZOJ_3365_[Usaco2004 Feb]Distance Statistics 路程统计&&POJ_1741_Tree_点分治 Description     在得知了自己农 ...

  4. 【poj1987】 Distance Statistics

    http://poj.org/problem?id=1987 (题目链接) 题意 给出一棵树,求树上距离不超过K的点对个数. Solution 点分治,同poj1741. 代码 // poj1987 ...

  5. BZOJ 3365 Distance Statistics 点分治

    这道题是一道点分治的题目,难度不大,可以拿来练手. 关键是对于找出来的重心的删除操作需要删掉这条边,这很重要. 还有每次找重心的时候,不但要考虑他的子节点的siz,还要考虑父节点的siz. 然后就A了 ...

  6. BZOJ 3365: [Usaco2004 Feb]Distance Statistics 路程统计

    Description 一棵树,统计距离不大于 \(k\) 的点对个数. Sol 点分治. 发现自己快把点分治忘干净了... 找重心使所有儿子的最大值尽量小,然后每次处理全部子树,再减去每个子树的贡献 ...

  7. bzoj 3365 [Usaco2004 Feb]Distance Statistics 路程统计(点分治,单调)

    [题意] 求树上长度不超过k的点对数目. [思路] 和 Tree 一样一样的. 就是最后统计的时候别忘把根加上. [代码] #include<set> #include<cmath& ...

  8. POJ 1987 Distance Statistics

    http://poj.org/problem?id=1987 题意:给一棵树,求树上有多少对节点满足距离<=K 思路:点分治,我们考虑把每个距离都存起来,然后排序,一遍扫描计算一下,注意还要减掉 ...

  9. POJ 1987 BZOJ 3365 Distance Statistics 树的分治(点分治)

    题目大意:(同poj1741,刷一赠一系列) CODE: #include <cstdio> #include <cstring> #include <iostream& ...

随机推荐

  1. 收集一些java相关的文章

    有些文章看了,以后想再看已经忘了在哪里了.故在此一一记录下那些值得看的文章. 1:如何确定Java对象的大小 中文版本 :http://article.yeeyan.org/view/104091/6 ...

  2. linux下利用nginx部署python网站

    首先目标机器需要安装python nginx uwsgi,其次,需要给Nginx写配置文件,大体内容如下,具体内容可见 http://blog.cn2p.com/web-server/nginx-uw ...

  3. monkey测试(转)

    一.Monkey测试简介Monkey测试是Android平台自动化测试的一种手段,通过Monkey程序模拟用户触摸屏幕.滑动Trackball.按键等操作来对设备上的程序进行压力测试,检测程序多久的时 ...

  4. Java的正则表达式

    package RegexTest; /** * Created by hu on 2016/3/29. */ /* * Java的正则表达式 在正则表达式中,用\d表示一位数字,如果在其它语言中使用 ...

  5. ajax基本用法

    ajax能做到无刷新数据交互,给用户体验带来好处的同时也减小了服务器的压力,所以运用ajax能使网站性能更强劲.更吸引用户. 大型网站少不了注册页面,而大多数情况下我们不想让用户有相同的注册ID,所以 ...

  6. VPN服务器的配置与应用

      实验场景 通过将Linux配置VPN服务器允许远程计算机能够访问内网. 我的目的: 现在需要开发第三方接口,而第三方接口有服务器IP地址鉴权配置,这样在本地开发出来的程序每次都要发布到服务器上测试 ...

  7. (转)SQL Server 2005 中的计算字段

    在实际工作上遇到的问题: 在订单表中有某项商品是将“订购数量(Quantity)”乘以“单件价格(UnitCost)”等于该项商品的总价(Subtotal). 在数据表中有的列(以下皆改叫为“字段”) ...

  8. java异常类

    package shb.java.exception; /** * 测试异常类 * @Package:shb.java.exception * @Description: * @author shao ...

  9. [转]IP动态切换脚本

    因为公司办公室要设置固定IP才行,而家里的IP段和公司是不一样的,家里采用了DHCP机制,这样每次就得改IP设置,很是不方便,就写了这个脚本来动态切换,很流畅的说!WINXP,WIN7测试通过~嘿嘿~ ...

  10. PAT乙级 1012. 数字分类 (20)

    1012. 数字分类 (20) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 给定一系列正整数,请按要求对数字进 ...