poj 1741
点分治入门题
首先发现是树上点对的问题,那么首先想到上点分治
然后发现题目要求是求出树上点对之间距离小于等于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的更多相关文章
- 【POJ 1741】 Tree (树的点分治)
Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 100 ...
- poj 1741 树的点分治(入门)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 18205 Accepted: 5951 Description ...
- POJ 1741 Tree 求树上路径小于k的点对个数)
POJ 174 ...
- poj 1741 Tree(树的点分治)
poj 1741 Tree(树的点分治) 给出一个n个结点的树和一个整数k,问有多少个距离不超过k的点对. 首先对于一个树中的点对,要么经过根结点,要么不经过.所以我们可以把经过根节点的符合点对统计出 ...
- poj 1741 楼教主男人八题之中的一个:树分治
http://poj.org/problem? id=1741 Description Give a tree with n vertices,each edge has a length(posit ...
- 树的点分治 (poj 1741, 1655(树形dp))
poj 1655:http://poj.org/problem?id=1655 题意: 给无根树, 找出以一节点为根, 使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子 ...
- POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量
POJ 1741. Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 34141 Accepted: 11420 ...
- 点分治——POJ 1741
写的第一道点分治的题目,权当认识点分治了. 点分治,就是对每条过某个点的路径进行考虑,若路径不经过此点,则可以对其子树进行考虑. 具体可以看menci的blog:点分治 来看一道例题:POJ 1741 ...
- POJ 1741 Tree(树的点分治,入门题)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 21357 Accepted: 7006 Description ...
- ●POJ 1741 Tree
题链: http://poj.org/problem?id=1741题解: 树上点分治. 入门题,不多说了. 代码: #include<cstdio> #include<cstrin ...
随机推荐
- JSP/JSF从web.xml中取出context-param的配置信息
JSP/JSF从web.xml中取出context-param的配置信息. 应用场景:我们配置了项目的版本信息,想让他显示在页面上,如: <context-param><!-- ## ...
- wx.request 使用数据
小程序中,怎么使用wx.request返回的数据??? 在你的js页面中 主要是这句话 var that=this; 为什么呢?因为使用过jquery的ajax的朋友都知道.在ajax函数中的this ...
- 微信小程序之:wepy(二)
一大堆实例:人家的博客园 代码规范: 1.尽量使用驼峰命名,避免使用$开头,框架内建属性都已$开头,可以使用this直接调用. 2.入口文件.页面.组件后缀都为.wpy. 3.使用ES6语法开发. 4 ...
- cucumber学习笔记
来源于cucumber官网 学习完了之后全部整理一遍
- 第三周博客作业<西北师范大学|李晓婷>
1.助教博客链接:https://www.cnblogs.com/lxt-/MyComments.html 2.学生作业打分要求: https://www.cnblogs.com/nwnu-dai ...
- windows类似grep的命令——findstr
windows类似grep的命令——findstr 使用Chrome发现访问google总是向香港那边跳转,估计配置文件中google网站映射的地址是www.google.com.hk,便想着改配 ...
- 【C#】 List按指定字段的给出的自定义顺序进行排序
#引言 有一个集合,对其进行排序,排序规则为:按对象中某个字段的特定顺序进行排序,比如:对象属性id,按照[4,2,5,1]的顺序排序: #代码: public class Foo { public ...
- You have an error in your SQL syntax; check the manual that corresponds to your MySQL server versio
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL ...
- EffectiveC++笔记 目录
Charpter 1. 让自己习惯C++ 条款01: 视C++为一个语言联邦 条款02: 尽量以const,enum,inline替换#define 条款03: 尽可能使用const 条款04: ...
- C# Datetime时间指定时区
string start_time_str = "2018-03-21 06:00:00"; DateTime.Parse(start_time_str) // :: 格林威治时间 ...