浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3784

难得地看了题解,发现居然还有点分序这么个玩意儿……

对于点分治时遍历过的点的长度为\(nlogn\)的序列,我们称它为点分序。

然后这题就是树上超级钢琴,在点分序上做就行了。对于每一条边,在点分序里能与其匹配的边是一段区间。

时间复杂度:\(O(nlogn*(1+log(nlogn)))\)

空间复杂度:\(O(nlogn*log(nlogn))\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std; const int maxn=5e4+5; bool vis[maxn];
int n,m,mx,rt,N,tot,cnt,L,R;
int now[maxn],pre[maxn*2],son[maxn*2],val[maxn*2];
int siz[maxn],a[maxn*20],Log[maxn*20],f[20][maxn*20]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} void add(int a,int b,int c) {
pre[++tot]=now[a];
now[a]=tot,son[tot]=b,val[tot]=c;
} struct node {
int v,pos,l,r; node() {} node(int _v,int _pos,int _l,int _r) {
v=_v,pos=_pos,l=_l,r=_r;
} bool operator<(const node &a)const {
return v<a.v;
}
}; struct Heap {
int tot;
node tree[maxn*26]; void ins(node res) {
tree[++tot]=res;
int pos=tot;
while(pos>1) {
if(tree[pos>>1]<tree[pos])
swap(tree[pos>>1],tree[pos]),pos>>=1;
else break;
}
} node pop() {
node res=tree[1];
tree[1]=tree[tot--];
int pos=1,son=2;
while(son<=tot) {
if(son<tot&&tree[son]<tree[son|1])son|=1;
if(tree[pos]<tree[son])
swap(tree[son],tree[pos]),pos=son,son=pos<<1;
else break;
}
return res;
}
}T; void find_rt(int fa,int u) {
int res=0;siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)find_rt(u,v),siz[u]+=siz[v],res=max(res,siz[v]);
res=max(res,N-siz[u]);
if(res<mx)mx=res,rt=u;
} void solve(int fa,int u,int dis) {
a[++cnt]=dis;T.ins(node(a[mx]+dis,cnt,L,R)),siz[u]=1;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]&&v!=fa)solve(u,v,dis+val[p]),siz[u]+=siz[v];
} void work(int u,int size) {
N=size,mx=rt=n+1,find_rt(0,u);
u=rt,vis[u]=1,a[++cnt]=0,L=cnt,mx=cnt;
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v]) {
R=cnt,solve(u,v,val[p]);
for(int j=R+1;j<=cnt;j++)
if(a[j]>a[mx])mx=j;
}
for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
if(!vis[v])work(v,siz[v]);
} int fake(int num1,int num2) {
if(a[num1]>a[num2])return num1;
return num2;
} int query(int l,int r) {
int x=Log[r-l+1];
return fake(f[x][l],f[x][r-(1<<x)+1]);
} void make_st() {
Log[0]=-1;
for(int i=1;i<=cnt;i++)
f[0][i]=i,Log[i]=Log[i>>1]+1;
for(int i=1;i<=19;i++)
for(int j=1;j+(1<<i)-1<=cnt;j++)
f[i][j]=fake(f[i-1][j],f[i-1][j+(1<<(i-1))]);
} int main() {
n=read(),m=read();
for(int i=1;i<n;i++) {
int a=read(),b=read(),c=read();
add(a,b,c),add(b,a,c);
}work(1,n),make_st();
for(int i=1;i<=m;i++) {
node tmp=T.pop();
int pos=query(tmp.l,tmp.r);
if(pos-1>=tmp.l)
T.ins(node(a[query(tmp.l,pos-1)]+a[tmp.pos],tmp.pos,tmp.l,pos-1));
if(pos+1<=tmp.r)
T.ins(node(a[query(pos+1,tmp.r)]+a[tmp.pos],tmp.pos,pos+1,tmp.r));
printf("%d\n",tmp.v);
}
return 0;
}

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

  1. BZOJ3784 : 树上的路径

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

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

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

  3. BZOJ3784树上的路径

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

  4. 【BZOJ3784】树上的路径 点分治序+ST表

    [BZOJ3784]树上的路径 Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a< ...

  5. 【BZOJ-3784】树上的路径 点分治 + ST + 堆

    3784: 树上的路径 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 462  Solved: 153[Submit][Status][Discuss ...

  6. codevs 2756树上的路径

    题意: 2756 树上的路径  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master    题目描述 Description 给出一棵树,求出最小的k,使得,且在树 ...

  7. bzoj 3784: 树上的路径 堆维护第k大

    3784: 树上的路径 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 88  Solved: 27[Submit][Status][Discuss] ...

  8. 树上的路径 BZOJ 3784

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

  9. Codevs 2756 树上的路径

    2756 树上的路径  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master     题目描述 Description 给出一棵树,求出最小的k,使得,且在树中存在 ...

随机推荐

  1. webStorm 多列编辑

    webStorm可以像Sublime一样使用列编辑,只是区别在于webStorm只可以编辑连续列表. 按住alt键鼠标选择一列,然后输入文字就会编辑多行,这个功能很赞,比较实用(按住ALT键选中之后, ...

  2. 【打CF,学算法——一星级】Codeforces Round #313 (Div. 2) A. Currency System in Geraldion

    [CF简单介绍] 提交链接:http://codeforces.com/contest/560/problem/A 题面: A. Currency System in Geraldion time l ...

  3. 必会必知git

    git必会必知   1 前言 git前身是BitKeeper,但是他不是开源软件,不符合当时开源趋势,于是就会有了开源的git,git开发只用了十天时间.目前git是公司开发必不可少的一个工具,用于多 ...

  4. CSDN专訪:大数据时代下的商业存储

    原文地址:http://www.csdn.net/article/2014-06-03/2820044-cloud-emc-hadoop 摘要:EMC公司作为全球信息存储及管理产品方面的率先公司,不久 ...

  5. mongodb 集群部署--分片服务器搭建

    部署分片服务器 1.分片 为了突破单点数据库服务器的I/O能力限制,对数据库存储进行水平扩展,严格地说,每一个服务器或者实例或者复制集就是一个分片. 2.优势 提供类似现行增·长架构 提高数据可用性 ...

  6. html学习笔记(2)-字母大小写转换练习

    主要应用了text-transform属性值: uppercase:所有单词的字母都大写: lowercase:所有单词的字母都小写: capitalize:每个单词的首字母都大写: none:默认值 ...

  7. php总结5——常量、文件上传

    5.1常量 系统常量: PHP_OS  操作系统 PHP_VERSION    php版本 PHP_SAPI    运行方式 自定义常量: define("常量名称"," ...

  8. 【题解】 P5022旅行

    [题解]P5022 旅行 当给定你一颗树的时候,这题就是一道送分题,凉心啊! 但是给定你一颗基环树呢? 暴力断环直接跑. 但是数据范围\(n\le 1000\) 乱做就完事了. 考场上这样想的,对于\ ...

  9. 【足迹C++primer】35、特定容器算法

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/cutter_point/article/details/33732681 特定容器算法 lst.me ...

  10. pm2 的使用

    pm2.json 代码如下 [{ "name" : "dingtalk-mobile", "script" : "app.js&q ...