点分治入门题

首先发现是树上点对的问题,那么首先想到上点分治

然后发现题目要求是求出树上点对之间距离小于等于k的对数,那么我们很自然地进行分类:

对于一棵有根树,树上的路径只有两种:一种经过根节点,另一种不经过根节点

对于经过根节点的路径,我们可以通过计算出每个点的根节点的距离,然后相加就能求出点对间距离

对于不经过根节点的路径,我们可以递归到子节点去算,去找子节点对应的子树来算即可

但是这里有两个问题:第一,如何快速算出以一个点为根的合法点对数量?

我们知道,可以在线性时间内求出每个点到根节点的距离,但如果我们逐个枚举点对的话,时间就会退化成平方级别

这显然不够优秀

所以我们将每个点到根节点距离排序,然后用两个指针,初始分别指向头和尾,如果两个指针指到的之和是合法的,那么这两个指针间的部分都是合法的(具体看代码),扫一遍即可

第二:这样做的结果是正确的吗?

我们看到,如果查到的一个点对在同一棵子树内,那么在计算以这个点为根和以这个点的子节点为根的时候,这个点对都会被计算一次!

这显然是不对的

因此我们在枚举每个子树时需要先去掉这一部分,然后再计算

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
struct Edge
{
int next;
int to;
int val;
}edge[];
int head[];
int rt,s;
int n,k;
int maxp[];
int siz[];
bool vis[];
int dis[];
int used[];
int ans=;
int cnt=;
void init()
{
memset(head,-,sizeof(head));
memset(vis,,sizeof(vis));
ans=;
cnt=;
}
void add(int l,int r,int w)
{
edge[cnt].next=head[l];
edge[cnt].to=r;
edge[cnt].val=w;
head[l]=cnt++;
}
void get_rt(int x,int fa)
{
siz[x]=,maxp[x]=;
for(int i=head[x];i!=-;i=edge[i].next)
{
int to=edge[i].to;
if(vis[to]||to==fa)continue;
get_rt(to,x);
siz[x]+=siz[to];
maxp[x]=max(maxp[x],siz[to]);
}
maxp[x]=max(maxp[x],s-siz[x]);
if(maxp[x]<maxp[rt])rt=x;
}
void get_dis(int x,int fa)
{
used[++used[]]=dis[x];
for(int i=head[x];i!=-;i=edge[i].next)
{
int to=edge[i].to;
if(vis[to]||to==fa)continue;
dis[to]=dis[x]+edge[i].val;
get_dis(to,x);
}
}
int calc(int x,int val)
{
dis[x]=val;
used[]=;
get_dis(x,);
sort(used+,used+used[]+);
int l=,r=used[];
int ret=;
while(l<r)
{
if(used[l]+used[r]<=k)ret+=r-l,l++;
else r--;
}
return ret;
}
void solve(int x)
{
vis[x]=;
ans+=calc(x,);
for(int i=head[x];i!=-;i=edge[i].next)
{
int to=edge[i].to;
if(vis[to])continue;
ans-=calc(to,edge[i].val);
rt=,s=siz[to],maxp[rt]=inf;
get_rt(to,);
solve(rt);
}
}
int main()
{
while()
{
scanf("%d%d",&n,&k);
init();
if(!n&&!k)return ;
for(int i=;i<n;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z),add(y,x,z);
}
maxp[rt]=s=n;
get_rt(,);
solve(rt);
printf("%d\n",ans);
}
return ;
}

poj 1741的更多相关文章

  1. 【POJ 1741】 Tree (树的点分治)

    Tree   Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...

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

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

  3. POJ 1741 Tree 求树上路径小于k的点对个数)

                                                                                                 POJ 174 ...

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

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

  5. poj 1741 楼教主男人八题之中的一个:树分治

    http://poj.org/problem? id=1741 Description Give a tree with n vertices,each edge has a length(posit ...

  6. 树的点分治 (poj 1741, 1655(树形dp))

    poj 1655:http://poj.org/problem?id=1655 题意: 给无根树,  找出以一节点为根,  使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子 ...

  7. POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量

    POJ 1741. Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 34141   Accepted: 11420 ...

  8. 点分治——POJ 1741

    写的第一道点分治的题目,权当认识点分治了. 点分治,就是对每条过某个点的路径进行考虑,若路径不经过此点,则可以对其子树进行考虑. 具体可以看menci的blog:点分治 来看一道例题:POJ 1741 ...

  9. POJ 1741 Tree(树的点分治,入门题)

    Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description ...

  10. ●POJ 1741 Tree

    题链: http://poj.org/problem?id=1741题解: 树上点分治. 入门题,不多说了. 代码: #include<cstdio> #include<cstrin ...

随机推荐

  1. linux shell set命令

    Linux set命令用于设置shell. set指令能设置所使用shell的执行方式,可依照不同的需求来做设置. 语法 set [+-abCdefhHklmnpPtuvx] 参数说明: -a 标示已 ...

  2. Mac 使用 OpenMP/Clang

    新建 hello.cpp 文件: #include <omp.h> #include <stdio.h> int main() { #pragma omp parallel p ...

  3. python学习日记(模块导入)

    什么是模块? 常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀. 但其实import加载的模块分为四个通用类别: 1 使用python编写的代码(.p ...

  4. python并发编程之多线程基础知识点

    1.线程理论知识 概念:指的是一条流水线的工作过程的总称,是一个抽象的概念,是CPU基本执行单位. 进程和线程之间的区别: 1. 进程仅仅是一个资源单位,其中包含程序运行所需的资源,而线程就相当于车间 ...

  5. django csrftoken

    CSRF(跨站请求伪造) 背景知识:浏览器在发送请求的时候,会自动带上当前域名对应的cookie内容,发送给服务端,不管这个请求是来源A网站还是其它网站,只要请求的是A网站的链接,就会带上A网站的co ...

  6. 集合源码分析[1]-Collection 源码分析

    目录 Collection 1. 介绍 2. 继承关系 3. 方法 4. JDK8新增的方法 removeIf(Predicate<? super E> filter) Spliterat ...

  7. 浅析redis缓存 在spring中的配置 及其简单的使用

    一:如果你需要在你的本地项目中配置redis.那么你首先得需要在你的本地安装redis 参考链接[http://www.runoob.com/redis/redis-install.html] 下载r ...

  8. 编写高质量的Python代码系列(六)之内置模块

    Python预装了许多写程序时会用到的重要模块.这些标准软件包与通常意义上的Python语言联系得非常精密,我们可以将其当成语言规范的一部分.本节将会讲解基本的内置模块. 第四十二条:用functoo ...

  9. Mathematica 代码

    s1 = ContourPlot3D[x^2 + z^2 == 1, {x, -1, 1}, {y, 0, 1}, {z, -1, 1}] s2 = ContourPlot3D[ y == 1 + S ...

  10. Gephi——使用map of countries和Geo Layout实现包含地理坐标的数据可视化

    前言: Gephi(以下内容基于0.9.2)比较擅长用来处理社会网络分析,其自身以及插件对地理数据的支持非常不足.主要有以下几点: 1.map of countries这个插件可以在gephi底图上以 ...