POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量
| Time Limit: 1000MS | Memory Limit: 30000K | |
| Total Submissions: 34141 | Accepted: 11420 |
Description
Define dist(u,v)=The min distance between node u and v.
Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k.
Write a program that will count how many pairs which are valid for a given tree.
Input
The last test case is followed by two zeros.
Output
Sample Input
5 4
1 2 3
1 3 1
1 4 2
3 5 1
0 0
Sample Output
8
题意就是给你一个带边权的树,求树上最短距离<=K的点对数量。树分治模板题。
代码:
//树分治-点分治
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf=1e9+;
const int maxn=1e5+; int head[maxn],tot;
int root,allnode,ans,n,k;
int vis[maxn],deep[maxn],dis[maxn],siz[maxn],point[maxn];//deep[0]子节点个数(路径长度),point为重心节点 struct node{
int to,next,val;
}edge[maxn<<]; void add(int u,int v,int w)//前向星存图
{
edge[tot].to=v;
edge[tot].next=head[u];
edge[tot].val=w;
head[u]=tot++;
} void init()//初始化
{
memset(head,-,sizeof head);
memset(vis,,sizeof vis);
tot=;
} void get_root(int u,int father)//重心
{
siz[u]=;point[u]=;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==father||vis[v]) continue;
get_root(v,u);//递归得到子树大小
siz[u]+=siz[v];
point[u]=max(point[u],siz[v]);//更新u节点的point
}
point[u]=max(point[u],allnode-siz[u]);//保存节点size
if(point[u]<point[root]) root=u;//更新当前子树的重心
} void get_dis(int u,int father)//获取子树所有节点与根的距离
{
deep[++deep[]]=dis[u];
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==father||vis[v]) continue;
int w=edge[i].val;
dis[v]=dis[u]+w;
get_dis(v,u);
}
} int cal(int u,int now)
{
dis[u]=now;deep[]=;
get_dis(u,);
sort(deep+,deep+deep[]+);
int all=;
for(int l=,r=deep[];l<r;){//二分
if(deep[l]+deep[r]<=k){
all+=r-l;l++;
}
else r--;
}
return all;
} void solve(int u)//以u为重心进行计算
{
ans+=cal(u,);//以当前u为重心的贡献
vis[u]=;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(vis[v]) continue;
ans-=cal(v,edge[i].val);//减去子树的影响
allnode=siz[v];
root=;
get_root(v,u);
solve(root);
}
} int main()
{
while(~scanf("%d%d",&n,&k)&&n&&k){
init();
for(int i=;i<n;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
root=ans=;
allnode=n;point[]=inf;
get_root(,);
solve(root);
printf("%d\n",ans);
}
return ;
}
一样的东西,就只是改了一下数据范围和输入格式。
代码:
//树分治-点分治
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int inf=1e9+;
const int maxn=4e4+; int head[maxn],tot;
int root,allnode,ans,n,k;
int vis[maxn],deep[maxn],dis[maxn],siz[maxn],point[maxn];//deep[0]子节点个数(路径长度),point为重心节点 struct node{
int to,next,val;
}edge[maxn<<]; void add(int u,int v,int w)//前向星存图
{
edge[tot].to=v;
edge[tot].next=head[u];
edge[tot].val=w;
head[u]=tot++;
} void init()//初始化
{
memset(head,-,sizeof head);
memset(vis,,sizeof vis);
tot=;
} void get_root(int u,int father)//重心
{
siz[u]=;point[u]=;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==father||vis[v]) continue;
get_root(v,u);//递归得到子树大小
siz[u]+=siz[v];
point[u]=max(point[u],siz[v]);//更新u节点的point
}
point[u]=max(point[u],allnode-siz[u]);//保存节点size
if(point[u]<point[root]) root=u;//更新当前子树的重心
} void get_dis(int u,int father)//获取子树所有节点与根的距离
{
deep[++deep[]]=dis[u];
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(v==father||vis[v]) continue;
int w=edge[i].val;
dis[v]=dis[u]+w;
get_dis(v,u);
}
} int cal(int u,int now)
{
dis[u]=now;deep[]=;
get_dis(u,);
sort(deep+,deep+deep[]+);
int all=;
for(int l=,r=deep[];l<r;){//二分
if(deep[l]+deep[r]<=k){
all+=r-l;l++;
}
else r--;
}
return all;
} void solve(int u)//以u为重心进行计算
{
ans+=cal(u,);//以当前u为重心的贡献
vis[u]=;
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].to;
if(vis[v]) continue;
ans-=cal(v,edge[i].val);//减去子树的影响
allnode=siz[v];
root=;
get_root(v,u);
solve(root);
}
} int main()
{
scanf("%d",&n);
init();
for(int i=;i<n;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
scanf("%d",&k);
root=ans=;
allnode=n;point[]=inf;
get_root(,);
solve(root);
printf("%d\n",ans);
return ;
}
POJ 1741.Tree and 洛谷 P4178 Tree-树分治(点分治,容斥版) +二分 模板题-区间点对最短距离<=K的点对数量的更多相关文章
- POJ1471 Tree/洛谷P4178 Tree
Tree P4178 Tree 点分治板子. 点分治就是直接找树的重心进行暴力计算,每次树的深度不会超过子树深度的\(\frac{1}{2}\),计算完就消除影响,找下一个重心. 所以伪代码: voi ...
- 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)
推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...
- 洛谷P4178 Tree (点分治)
题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下 ...
- 洛谷 P4178 Tree —— 点分治
题目:https://www.luogu.org/problemnew/show/P4178 这道题要把 dep( dis? ) 加入一个 tmp 数组里,排序,计算点对,复杂度很美: 没有写 sor ...
- 洛谷P4178 Tree (算竞进阶习题)
点分治 还是一道点分治,和前面那道题不同的是求所有距离小于等于k的点对. 如果只是等于k,我们可以把重心的每个子树分开处理,统计之后再合并,这样可以避免答案重复(也就是再同一个子树中出现路径之和为k的 ...
- 2018.07.20 洛谷P4178 Tree(点分治)
传送门 又一道点分治. 直接维护子树内到根的所有路径长度,然后排序+双指针统计答案. 代码如下: #include<bits/stdc++.h> #define N 40005 using ...
- [洛谷P4178]Tree
题目大意:给一棵树,问有多少条路径长度小于等于$k$ 题解:点分治 卡点:无 C++ Code: #include <cstdio> #include <algorithm> ...
- 洛谷 P4178 Tree
#include<iostream> #include<cstdlib> #include<cstdio> #include<cmath> #inclu ...
- [洛谷P4178] Tree (点分治模板)
题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...
随机推荐
- FastJson前置属性过滤器
FastJson前置属性过滤器 /** * <html> * <body> * <P> Copyright 1994 JsonInternational</p ...
- RStudio中安装factoextra包的问题
最近在做一个R语言的小作业,其中聚类分析部分需要用到factoextra安装包,在RStudio中输入install.packages("factoextra")之后,就一直出现“ ...
- 2019 昆仑万维java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.昆仑万维等公司offer,岗位是Java后端开发,因为发展原因最终选择去了昆仑万维,入职一年时间了,也成为了面 ...
- Kubernetes第十一章--部署微服务电商平台
- python全栈学习路线
python全栈学习路线-查询笔记 查询目录 一,硬件 十一,数据 ...
- mysql DML select查询
windows上的操作 1.从官网下载mysql 下载navicat,用来连接mysql的 2.打开运行启动mysql 3.在navicat上的连接打开新建连接 然后输入链接名,连接名就是用户名,自己 ...
- 使用FMXlinux 开发linux 桌面应用
自从delphi 10.2 开始正式支持linux 开发来,大家一直关心为什么官方没有使用FMX来支持LInux 的桌面开发? 其实原因无非就几点: 1.Linux 大部分是应用还是服务端的,桌面应 ...
- PDF 补丁丁 0.6.2.3572 测试版发布
近日有网友反馈 3571 测试版的补丁丁无法正常工作.请下载新发布的 3572 版本.
- git 列出两个分支 或者两个提交版本之间不同的文件名字
只列出名字 git diff remotes/origin/dev remotes/origin/master --name-only
- <choose><when><if>
--说明:choose类似于switch,其中的when如果不符合则进入otherwise(类似于default),可以结合if标签使用. -- <select> -- SELECT * ...