题目大意

给定一个\(N\)个结点的树,结点用正整数\(1..N\)编号。每条边有一个正整数权值。用\(d(a,b)\)表示从结点\(a\)到结点\(b\)路边上经过边的权值。其中要求\(a < b.\)将这\(n*(n-1)/2\)个距离从大到小排序,输出前\(M\)个距离值。

题目分析

统计树上路径的问题显然需要淀粉质(好毒瘤啊,连续考了两天点分治)。

由于前\(M\)大路径难以直接统计,而我们又很擅长统计长度大于\(l\)的路径个数,因此考虑首先二分答案求出第\(M\)大路径的长度\(l\),再统计长度大于\(l\)的路径。

分析一波时间复杂度,点分\(O(n\ logn)\),统计路径时为了方便,我们需要排序后二分(又一个\(logn\)),本身二分答案就是\(logn\),这样一来时间复杂度达到了\(O(n\ log^3n)\),难以接受。

考试的时候想到一些小优化,如把点分后的每一个子树的根记录下来。当时也想到了把路径存下来,但不知道为什么就认为空间复杂度不正确立马否定掉了。实际上就是要将路径存下来,而且空间复杂度为\(O(n\ logn)\)。这样我们只需要最初建好点分树并排好序,每次只需要对每一个点为根的路径二分一下\(O(n\ logn)\),如此一来算法的时间复杂度瓶颈为\(O(n\ log^2n)\),本题得到完美解决。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Maxn=50005;
int n,m,h[Maxn],G[Maxn];
int rt,root,totsize,size[Maxn],mx[Maxn];
int lim,path[Maxn];ll ans;
vector<int>v[Maxn],g[Maxn],Ans;
bool vis[Maxn];
struct edge{int to,next,w;}e[Maxn*2],f[Maxn*2];
int getint(){
int w=0,f=1;char ch=getchar();
while(!isdigit(ch))ch!='-'?:f=-1,ch=getchar();
while(isdigit(ch))w=w*10+ch-'0',ch=getchar();
return w*f;
}
void addedge(int x,int y,int z){
static int cnt;
e[++cnt]=(edge){y,h[x],z};h[x]=cnt;
}
void AddEdge(int x,int y){
static int cnt;
f[++cnt]=(edge){y,G[x]};G[x]=cnt;
}
void getroot(int x,int fa){
size[x]=1;mx[x]=0;
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(vis[y]||y==fa)continue;
getroot(y,x);
size[x]+=size[y];
mx[x]=max(mx[x],size[y]);
}
mx[x]=max(mx[x],totsize-size[x]);
if(mx[x]<mx[root])root=x;
}
void getsize(int x,int fa){
totsize++;
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(vis[y]||y==fa)continue;
getsize(y,x);
}
}
void dfs(int x,int fa,int dis,vector<int>&v){
v.push_back(dis);
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(vis[y]||y==fa)continue;
dfs(y,x,dis+e[i].w,v);
}
}
void Build(int x){
vis[x]=1;v[x].push_back(0);
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(vis[y])continue;
dfs(y,x,e[i].w,v[x]);
}
sort(v[x].begin(),v[x].end());
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(vis[y])continue;
totsize=root=0;
getsize(y,x);getroot(y,x);
dfs(y,x,e[i].w,g[root]);
sort(g[root].begin(),g[root].end());
AddEdge(x,root);Build(root);
}
}
ll calc(vector<int>&v){
ll ret=0;
for(int i=0;i<v.size();i++)ret+=v.end()-lower_bound(v.begin(),v.end(),lim-v[i]);
return ret;
}
void solve(int x){
ans+=calc(v[x]);
for(int i=G[x];i;i=f[i].next){
int y=f[i].to;
ans-=calc(g[y]);
}
if(ans>=m)return;
for(int i=G[x];i;i=f[i].next){
int y=f[i].to;
solve(y);
}
}
bool Judge(int mid){
lim=mid;ans=0;
solve(rt);
return ans>=m*2;
}
void dfs2(int x,int fa,int dis){
path[++path[0]]=dis;
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(vis[y]||y==fa)continue;
dfs2(y,x,dis+e[i].w);
}
}
void Count(int x){
path[0]=0;path[++path[0]]=0;
for(int i=h[x];i;i=e[i].next){
int y=e[i].to;
if(vis[y])continue;
int now=path[0];
dfs2(y,x,e[i].w);
for(int j=now+1;j<=path[0];j++){
int pos=lower_bound(path+1,path+now+1,lim-path[j])-path;
for(int k=pos;k<=now;k++)Ans.push_back(path[j]+path[k]);
}
sort(path+now+1,path+path[0]+1);
inplace_merge(path+1,path+now+1,path+path[0]+1);
}
}
void solve2(int x){
vis[x]=1;Count(x);
for(int i=G[x];i;i=f[i].next){
int y=f[i].to;
solve2(y);
}
}
int main(){
n=getint();m=getint();
for(int i=1;i<n;i++){
int x=getint(),y=getint(),z=getint();
addedge(x,y,z);addedge(y,x,z);
}
mx[0]=n+1;totsize=n;root=0;
getroot(1,0);rt=root;
Build(root);
int l=0,r=5e8;
while(l<=r){
int mid=(l+r)>>1;
if(Judge(mid))l=mid+1;
else r=mid-1;
}
memset(vis,0,sizeof(vis));
lim=l;ans=0;solve2(rt);
while(Ans.size()<m)Ans.push_back(l-1);
sort(Ans.begin(),Ans.end(),greater<int>());
for(int i=0;i<m;i++)cout<<Ans[i]<<"\n";
}

【BZOJ3784】树上路径的更多相关文章

  1. hihocoder[Offer收割]编程练习赛19 D 相交的铁路线(树上路径交)

    傻逼题... 裸的树上路径交 两条树上的路径$[a,b]$和$[c,d]$有交,则有$lca(a,b)$在$[c,d]$上或$lca(c,d)$在$[a,b]$上. 其实只要深度大的$lca$在另一条 ...

  2. 树上路径(path)

    树上路径(path) 题目描述 在Berland,有n个城堡. 每个城堡恰好属于一个领主.不同的城堡属于不同的领主.在所有领主中有一个是国王,其他的每个领主都直接隶属于另一位领主,并且间接隶属于国王. ...

  3. 某模拟赛C题 树上路径统计 (点分治)

    题意 给定一棵有n个节点的无根树,树上的每个点有一个非负整数点权.定义一条路径的价值为路径上的点权和-路径上的点权最大值. 给定参数P,我!=们想知道,有多少不同的树上简单路径,满足它的价值恰好是P的 ...

  4. 【JZOJ4715】【NOIP2016提高A组模拟8.19】树上路径

    题目描述 给出一棵树,求出最小的k,使得,且在树中存在路径p,使得k>=S且k<=E.(k为路径p上的边的权值和) 输入 第一行给出N,S,E.N代表树的点数,S,E如题目描述. 下面N- ...

  5. BZOJ3784 : 树上的路径

    树的点分治,在分治的时候将所有点到根的距离依次放入一个数组q中. 对于一棵子树里的点,合法的路径一定是q[L]..q[R]的某个数加上自己到重心的距离. 定义五元组(v,l,m,r,w),表示当前路径 ...

  6. 2019.01.20 bzoj3784: 树上的路径(二分答案+点分治)

    传送门 点分治好题. 题意简述:给一棵带边权的树,问所有路径中前mmm大的.m≤300000m\le300000m≤300000 思路: 网上有题解写了可以通过什么点分治序转化成超级钢琴那道题的做法蒟 ...

  7. BZOJ3784树上的路径

    题目描述 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距离从大到小排序, ...

  8. SPOJ-COT-Count on a tree(树上路径第K小,可持久化线段树)

    题意: 求树上A,B两点路径上第K小的数 分析: 同样是可持久化线段树,只是这一次我们用它来维护树上的信息. 我们之前已经知道,可持久化线段树实际上是维护的一个前缀和,而前缀和不一定要出现在一个线性表 ...

  9. POJ 1741 Tree 求树上路径小于k的点对个数)

                                                                                                 POJ 174 ...

随机推荐

  1. PIE SDK元素事件的监听

    1功能简介 元素在操作的过程中,如添加,删除,选中等操作都需要有事件的监听,PIE SDK支持对元素操作事件的监听,下面对元素事件的监听进行介绍. 2功能实现说明 2.1.1 实现思路及原理说明 第一 ...

  2. 2.Exadata 硬件体系结构

    Exadata 硬件加构: 高性能,低成本 冗余 线性扩展 ,具有超强性能,开箱即用         例 2-2的满配: 8台数据服务器组成(2C 6核) (3-2是10核, 4-2,5-2 是12核 ...

  3. java将list<T>导出为xls文件

    一.action层 /** * 导出list */ @SuppressWarnings("unchecked") public void exportBatch() { reque ...

  4. 【3dsMax安装失败,如何卸载、安装3dMax 2011?】

    AUTODESK系列软件着实令人头疼,安装失败之后不能完全卸载!!!(比如maya,cad,3dsmax等).有时手动删除注册表重装之后还是会出现各种问题,每个版本的C++Runtime和.NET f ...

  5. vue中添加util公共方法&&ES6之import、export

    vue中添加util公共方法&&ES6之import.export https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Re ...

  6. JQuery实现表格的全选和反选,以及分页勾选保存(laypage插件分页的使用)

    需求: 1.全选与取消全选 2.单个勾选,点击表格单元格中checkbox勾选,也可以在点击行勾选,便与用户操作 3.分页勾选保存 4.固定表头 功能一: 说明:操作全选按钮的同时,遍历每一个tr中的 ...

  7. yum安装git

    此方法对于RHEL.Fedora.CentOS有效: 1.yum install git 2.yum istall git-svn git-email git-gui gitk

  8. Oracle中查询关键字select--from--where--group by--having--order by执行顺序

    select--from--where--group by--having--order by 这6个查询关键字的执行顺序: 1.from组装来自不同数据源的数据:2.where基于指定的条件对记录行 ...

  9. VHDL

    数字逻辑VHDL 信号与变量 signal是全局的,在整个结构体中都有效,它的赋值是在进程结束, 也就是最后的赋值是有效的. variable是局部的,它的赋值是立即生效的. 一般变量是在进程的说明部 ...

  10. C#委托的好处

    C#委托的好处 先来看一个例子: 某人有三子,让他们各自带一样东西出门,并带回一头猎物. 可以理解为一种父亲对儿子的委托: 猎物  办法(工具 某工具) 三个人执行委托的方法各不相同 兔子 打猎(工具 ...