【xsy1197】 树 二分+点分树+二分
题目大意:给你一棵$n$个点的带权树和正整数$K$,求每个点到其它所有点距离中第$K$大的数值。
其中,边权$≤10000$,$n≤50000$。
我们通过原树构建一棵点分治树,令$fa[u]$为$u$在点分树上的$father$。
对于每个点$u$,我们维护两个有序数组$f$和$g$。
其中$f[i]$表示以$u$为根的点分树中,距离$u$第$i$近的距离。(显然里面有$siz[u]$个数值)
$g[i]$表示以$u$为根的点分树中,距离$fa[u]$第i近的距离。
我们二分答案,设当前二分到的值为$p$,我们要求所有与$u$距离$≤p$的数量。
然后答案显然为$\sum_{v∈ancestor[u]} (\sum_{f[v][i]≤p-dis(v,u)}1-\sum_{g[v][i]≤p-dis(fa[v],u)}1)$
这样单次询问的时间复杂度显然是$O(log^3n)$的。
然后时间复杂度就是$O(n\ log^3\ n)$。
完结撒花
#include<bits/stdc++.h>
#define M 50005
#define INF 19890604
using namespace std; struct edge{int u,v,next;}e[M*]={}; int head[M]={},use=;
void add(int x,int y,int z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
int n,k;
int f[M][]={},d[M]={},dep[M]={}; void dfs(int x,int fa){
f[x][]=fa; dep[x]=dep[fa]+;
for(int i=;i<;i++) f[x][i]=f[f[x][i-]][i-];
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
d[e[i].u]=d[x]+e[i].v;
dfs(e[i].u,x);
}
}
int getlca(int x,int y){
if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y];
for(int i=;~i;i--) if((<<i)&cha) x=f[x][i];
for(int i=;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
if(x==y) return x; return f[x][];
}
int getdis(int x,int y){
int lca=getlca(x,y);
return d[x]+d[y]-*d[lca];
} int vis[M]={},siz[M]={},minn=INF,minid=;
void dfssiz(int x,int fa){
siz[x]=;
for(int i=head[x];i;i=e[i].next)
if(e[i].u!=fa&&vis[e[i].u]==){
dfssiz(e[i].u,x);
siz[x]+=siz[e[i].u];
}
}
void dfsmin(int x,int fa,int fsiz){
int maxn=fsiz-siz[x];
for(int i=head[x];i;i=e[i].next)
if(e[i].u!=fa&&vis[e[i].u]==){
dfsmin(e[i].u,x,fsiz);
maxn=max(maxn,siz[e[i].u]);
}
if(maxn<minn) minn=maxn,minid=x;
}
int makeroot(int x){
dfssiz(x,);
minn=INF; minid=;
dfsmin(x,,siz[x]);
return minid;
}
vector<int> F[M],G[M]; void addvec(int x,int fa,int X,int FA,int nowdis){
F[X].push_back(getdis(x,X));
G[X].push_back(getdis(x,FA));
for(int i=head[x];i;i=e[i].next)
if(e[i].u!=fa&&vis[e[i].u]==)
addvec(e[i].u,x,X,FA,nowdis+e[i].v);
}
int fa[M]={};
void build(int x,int Fa){
x=makeroot(x); vis[x]=; fa[x]=Fa;
addvec(x,fa[x],x,fa[x],);
sort(F[x].begin(),F[x].end());
sort(G[x].begin(),G[x].end());
for(int i=head[x];i;i=e[i].next) if(vis[e[i].u]==){
build(e[i].u,x);
}
} bool check(int x,int mid){
int res=-,X=x;
for(;x;x=fa[x]){ res+=upper_bound(F[x].begin(),F[x].end(),mid-getdis(X,x))-F[x].begin();
if(fa[x]) res-=upper_bound(G[x].begin(),G[x].end(),mid-getdis(X,fa[x]))-G[x].begin();
}
return res>=k;
} int main(){
scanf("%d%d",&n,&k);
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);
}
dfs(,);
build(,);
for(int i=;i<=n;i++){
int l=,r=*n;
while(l<r){
int mid=(l+r)>>;
if(check(i,mid)) r=mid;
else l=mid+;
}
printf("%d\n",l);
}
}
【xsy1197】 树 二分+点分树+二分的更多相关文章
- 一篇自己都看不懂的点分治&点分树学习笔记
淀粉质点分治可真是个好东西 Part A.点分治 众所周知,树上分治算法有$3$种:点分治.边分治.链分治(最后一个似乎就是树链剖分),它们名字的不同是由于分治方式的不同的.点分治,顾名思义,每一次选 ...
- BZOJ4317Atm的树&BZOJ2051A Problem For Fun&BZOJ2117[2010国家集训队]Crash的旅游计划——二分答案+动态点分治(点分树套线段树/点分树+vector)
题目描述 Atm有一段时间在虐qtree的题目,于是,他满脑子都是tree,tree,tree…… 于是,一天晚上他梦到自己被关在了一个有根树中,每条路径都有边权,一个神秘的声音告诉他,每个点到其他的 ...
- [BZOJ4552][TJOI2016&&HEOI2016]排序(二分答案+线段树/线段树分裂与合并)
解法一:二分答案+线段树 首先我们知道,对于一个01序列排序,用线段树维护的话可以做到单次排序复杂度仅为log级别. 这道题只有一个询问,所以离线没有意义,而一个询问让我们很自然的想到二分答案.先二分 ...
- [CTSC2018]混合果汁(二分答案+主席树)
考场上写了60分的二分答案,又写了15分的主席树,然后就弃了.. 合起来就A了啊!主席树忘了开20倍空间最后还炸掉了. 最水的签到题被我扔了,主要还是不会用线段树求前缀和. 做法应该是比较显然的,首先 ...
- 【Luogu】P2824排序(二分答案+线段树排序)
题目链接 震惊!两个线段树和一个线段树竟是50分的差距! 本题可以使用二分答案,二分那个位置上最后是什么数.怎么验证呢? 把原序列改变,大于等于mid的全部变成1,小于mid的全部变成0,之后线段树排 ...
- cogs 2109. [NOIP 2015] 运输计划 提高组Day2T3 树链剖分求LCA 二分答案 差分
2109. [NOIP 2015] 运输计划 ★★★☆ 输入文件:transport.in 输出文件:transport.out 简单对比时间限制:3 s 内存限制:256 MB [题 ...
- Trace 2018徐州icpc网络赛 (二分)(树状数组)
Trace There's a beach in the first quadrant. And from time to time, there are sea waves. A wave ( xx ...
- BZOJ4538 HNOI2016网络(树链剖分+线段树+堆/整体二分+树上差分)
某两个点间的请求只对不在这条路径上的询问有影响.那么容易想到每次修改除该路径上的所有点的答案.对每个点建个两个堆,其中一个用来删除,线段树维护即可.由于一条路径在树剖后的dfs序中是log个区间,所以 ...
- Codeforces Round #276 (Div. 1) E. Sign on Fence (二分答案 主席树 区间合并)
链接:http://codeforces.com/contest/484/problem/E 题意: 给你n个数的,每个数代表高度: 再给出m个询问,每次询问[l,r]区间内连续w个数的最大的最小值: ...
随机推荐
- android触控,先了解MotionEvent(一)
http://my.oschina.net/banxi/blog/56421 这是我个人的看法,要学好android触控,了解MotionEvent是必要,对所用的MotionEvent常用的API要 ...
- Basic4android v3.80 beta 发布
增加了条件编译,共享模块,部分支持jar 文件直接访问.还有其他一些更新. I'm happy to release B4A v3.80 BETA. This version includes sev ...
- 2018.08.20 loj#117. 有源汇有上下界最小流(模板)
传送门 这题真有意思... 先是有一个点T的我怀疑人生. 然后学大佬们封装了我的dinic就莫名其妙的过了??? 所以说锅给谁好呢? 给dinic吧... 解法就是先求出一段可行流,然后从t到s加一条 ...
- Django入门指南-第10章:Django Admin 介绍(完结)
在浏览器中打开该URL:http://127.0.0.1:8000/admin/ 我们可以检查一切是否正常,打开URL http://127.0.0.1:8000 我们首先创建一个管理员帐户: pyt ...
- S3 exercise -- 文件操作&函数
编码 请说明python2 与python3中的默认编码是什么? # 答案 py2默认ASCII码,py3默认的utf8 为什么会出现中文乱码?你能列举出现乱码的情况有哪几种? # 答案 #codin ...
- Error setting expression 'XXX‘'[Ljava.lang.with value '[Ljava.lang.String;@10101fb'
ognl报的警告,说明你的格式错误,一般是日期格式错误,格式转换器的应用,id设置的类型不对String 类型,输入了Int类型所以方法一是改变这个类中的id的属性 然后get和set也跟着改变 另一 ...
- HDU 1087 Super Jumping! Jumping! Jumping! (DP+LIS)
题意:给定一个长度为n的序列,让你求一个和最大递增序列. 析:一看,是不是很像LIS啊,这基本就是一样的,只不过改一下而已,d(i)表示前i个数中,最大的和并且是递增的, 如果 d(j) + a[i] ...
- Linux将程序添加到服务的方法(通用)
一:咱们通过这篇文章来演示怎么将某个程序作为服务(就类似Windows服务可以开机自动启动),这里以tomcat为例,已经亲测过: 二:步骤(最好用root用户来做这种事情,切换root用户记得su ...
- MongoDB操作数据库的几个命令(自己用)
本文以配置百度的Clouda为源头:http://cloudajs.org/docs 继而安装node.js:http://nodejs.org/download/(直接安装,简单) 和MongoDB ...
- 获取iOS 设备上崩溃日志 (Crash Log)的方法
1. iTunes同步获取 大部分用户会使用iTunes软件来管理iPhone,这样同步的Crash日志就会同步到电脑上,我们需要在特定的路径里面查找 Mac OS X:~/Library/Logs/ ...