点分治【bzoj1468】 Tree
点分治【bzoj1468】 Tree
Description
给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K
Input
N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k
Output
一行,有多少对点之间的距离小于等于k
点分治开始入门。
点分治,主要是解决形如:给你一棵树,求树上满足XX条件的点对的对数。
所以说应对的问题很多时候都和树形DP相同。
首先告诉自己,分治是高效的算法。
想一下,平时在面对普通的分治问题,每次肯定都是半分,直到成为小问题,然后再分别解决。
为了保证点分治的高效,所以我们每一次应该将当前问题分成最平均的两个问题,放到树上就是指我们要将当前的树分成大小最平均的几棵。
那么就可以引入一个概念:树的重心。定义是在树上找一个点作为根,使得子树中的size最大者最小,这样我们就可以很好的将树平均分。
所以解决点分治问题的基本思路也就有了:
我们从整棵树开始,每一次找到当前树的重心并且以他为根,也就是将无根树转成有根树,然后对于当前的树,我们只对与当前树的根的点对进行处理。
对于这道题来说,就是找到路径经过当前根的点对,去统计这些点对中符合条件的数量对答案作出贡献。
然后对于每个子树,向下分治,继续找重心……
另外,和【bzoj3365】是一样的题。
code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int wx=40017;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int n,m,ans,num,root,k,tmp;
int head[wx],dis[wx],size[wx];
int f[wx],vis[wx];
int temp[wx];
struct e{
int nxt,to,dis;
}edge[wx*2];
void add(int from,int to,int dis){
edge[++num].nxt=head[from];
edge[num].to=to;
edge[num].dis=dis;
head[from]=num;
}
void getroot(int u,int fa){
size[u]=1;f[u]=0;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
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],tmp-size[u]);
if(f[root]>f[u])root=u;
}
void dfs(int u,int fa){
temp[++temp[0]]=dis[u];
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa||vis[v])continue;
dis[v]=dis[u]+edge[i].dis;
dfs(v,u);
}
}
int calc(int u,int now){
dis[u]=now;temp[0]=0;dfs(u,0);
int l=1,r=temp[0];int re=0;
sort(temp+1,temp+temp[0]+1);
while(l<r){
if(temp[r]+temp[l]<=k)re+=r-l,l++;
else r--;
}
return re;
}
void slove(int u){
vis[u]=1;ans+=calc(u,0);
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(vis[v])continue;
ans-=calc(v,edge[i].dis);
root=0;tmp=size[v];getroot(v,0);slove(root);
}
}
int main(){
n=read();
for(int i=1;i<n;i++){
int x,y,z;
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
k=read();
f[0]=(1<<30);tmp=n;
getroot(1,0);
slove(root);
printf("%d\n",ans);
return 0;
}
点分治【bzoj1468】 Tree的更多相关文章
- POJ1741 Tree + BZOJ1468 Tree 【点分治】
POJ1741 Tree + BZOJ1468 Tree Description Give a tree with n vertices,each edge has a length(positive ...
- P4169-CDQ分治/K-D tree(三维偏序)-天使玩偶
P4169-CDQ分治/K-D tree(三维偏序)-天使玩偶 这是一篇两种做法都有的题解 题外话 我写吐了-- 本着不看题解的原则,没写(不会)K-D tree,就写了个cdq分治的做法.下面是我的 ...
- BZOJ1468:Tree(点分治)
Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是 ...
- 洛谷4178 BZOJ1468 Tree题解点分治
点分治的入门练习. 题目链接 BZOJ的链接(权限题) 关于点分治的思想我就不再重复了,这里重点说一下如何判重. 我们来看上图,假设我们去除了1节点,求出d[2]=1,d[3]=d[4]=2 假设k为 ...
- 【点分治】bzoj1468 Tree
同poj1741. 换了个更快的姿势,不会重复统计然后再减掉什么的啦~ #include<cstdio> #include<algorithm> #include<cst ...
- bzoj1468 Tree
最经典的点分治题目,在递归子树的时候减去在算父亲时的不合法方案. #include<iostream> #include<cstdio> #include<cstring ...
- POJ3714 Raid 分治/K-D Tree
VJ传送门 简要题意:给出两个大小均为\(N\)的点集\(A,B\),试在\(A\)中选择一个点,在\(B\)中选择一个点,使得它们在所有可能的选择方案中欧几里得距离最小,求出这个距离 下面给出的两种 ...
- BZOJ1468: Tree & BZOJ3365: [Usaco2004 Feb]Distance Statistics 路程统计
[传送门:BZOJ1468&BZOJ3365] 简要题意: 给出一棵n个点的树,和每条边的边权,求出有多少个点对的距离<=k 题解: 点分治模板题 点分治的主要步骤: 1.首先选取一个点 ...
- 【BZOJ-1468】Tree 树分治
1468: Tree Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1025 Solved: 534[Submit][Status][Discuss] ...
随机推荐
- jitter buffer QoS的解决方案
本文主要介绍一种QoS的解决方案,文章来自博客园RTC.Blacker,欢迎关注微信公众号blacker,更多详见www.rtc.help QoS出现的背景: 而当网络发生拥塞的时候,所有的数据流都有 ...
- poj3252 Round Numbers[数位DP]
地址 拆成2进制位做dp记搜就行了,带一下前导0,将0和1的个数带到状态里面,每种0和1的个数讨论一下,累加即可. WA记录:line29. #include<iostream> #inc ...
- NSSet 用法
//集合NSSet //集合也是储存对象,和字典一样也是无序存储 //集合中里面的元素不能重复 //集合里面的元素可以随机取出 //用数组放到集合中 NSArray *a10 = @[p1 , p2 ...
- hdu 5616 Jam's balance 正反背包+转换
http://acm.hdu.edu.cn/showproblem.php?pid=5616 思路 题目中蕴含着两种需要计算的重量 1. 从所有的砝码中挑出任意种2.(转换的思想)在天平的两端都挑出这 ...
- xshell 登录虚拟机ubuntu
本地装的Ubuntu虚拟机. 宿主机是win10, 互相之间能ping通,就是Xshell连不上,而且也不能弹出用户名和密码框. 后来解决,具体过程如下: 1: ifconfig -a命令得到 ...
- LAMP 1.2 Apache编译安装问题解决
这个错误安装 yum install -y gcc error: mod_deflate has been requested but can not be built due to prerequi ...
- JDBC初步
public class TestMySqlConnection{ public static void main(String[] args){ Class.forNa ...
- Linux Screen超简明教程
1.安装Screen 大多数情况下,系统已经安装好了screen.如果没有,可以用下面的命令来安装: CentOS系统中执行:yum install screen Debian/Ubuntu系统执行: ...
- [xdoj1158]阶乘求逆元(常用于求组合数)
http://acm.xidian.edu.cn/problem.php?id=1158 解题关键:此题注意将$\sum\limits_{i = 0}^x {C_x^iC_y^{i + k}}$转化为 ...
- Dockerfile设置apt-get install tzdata的noninteractive方法
在Ubuntu系统中,执行命令apt-get install -y tzdata以安装tzdata软件包.但是,最近发现,在Ubuntu 18.04 (Bionic Beaver)上无法自动安装该软件 ...