点分治入门题

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

然后发现题目要求是求出树上点对之间距离小于等于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. 2018 API变化

  2. FWT(快速沃尔什变换)小结

    在多项式卷积的处理中,我们实际上实现的是下面的一个式子 \[ C_k=\sum_{i+j=k}A_iB_j \] 然而事实上有些和(sang)蔼(xin)可(bing)亲(kuang)的出题人,并不会 ...

  3. bzoj 2002 : [Hnoi2010]Bounce 弹飞绵羊 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2002 题面: 2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: ...

  4. MT【327】两道不等式题

    当$x,y\ge0,x+y=2$时求下面式子的最小值:1)$x+\sqrt{x^2-2x+y^2+1}$2)$\dfrac{1}{5}x+\sqrt{x^2-2x+y^2+1}$ 解:1)$P(x,y ...

  5. python学习日记(继承和多态)

    继承 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类(Base class.S ...

  6. ADC采样工作原理详解

    如何利用单片机的ADC模块(或者独立的ADC芯片)得到接入ADC管脚上的实际电压值?这个问题,是第一次接触ADC时候,大家都会遇到的问题.会读到什么值单片机会读到什么值?需要看一个特性,就是几位的AD ...

  7. 介绍一款自动给添加不同浏览器CSS3前缀的插件~Autoprefixer(附其他前端开发插件)

    正文 自动给CSS文件添加不同浏览器的CSS3前缀:Autoprefixer 安装 只需兼容主流浏览器 正常情况使用:(在书写完的CSS样式文件中,按F1,选择Autoprefixer CSS) 这时 ...

  8. [SDOI2017]遗忘的集合

    [SDOI2017]遗忘的集合 综合了很多套路的题 一看就是完全背包 生成函数! 转化为连乘积形式 Pi....=F 求Ln! 降次才可以解方程 发现方程是: f[i]=∑t|i : bool(t)* ...

  9. codeblocks(其它软件)修改后缀文件的打开默认方式

  10. mysql 在visual studio中的配置

    视图-->其他窗口-->服务器资源管理器-->数据连接-->右键添加连接 servername:localhost username:root password:123456 ...