【BZOJ-3784】树上的路径 点分治 + ST + 堆
3784: 树上的路径
Time Limit: 10 Sec Memory Limit: 256 MB
Submit:
462 Solved: 153
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
1 2 1
1 3 2
2 4 3
2 5 4
Sample Output
7
6
5
4
4
3
3
2
1
HINT
N<=50000,M<=Min(300000,n*(n-1) /2
Source
Solution
超级钢琴推广到树上版本
利用点分治每个点的时间戳,将树转化到序列上,顺带记录每个节点,能和他组成一条路径的左右端点L,R
然后利用超级钢琴的方法去处理就好,具体见这里
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 100010
#define MAXM 1000100
int N,M;
struct EdgeNode{int next,to,val;}edge[MAXN<<];
int head[MAXN],cnt=;
void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].val=w;}
void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);}
int maxx[MAXN],size[MAXN],Sz,root,L[MAXM],R[MAXM],D[MAXM],pl,pr,dfn;
bool visit[MAXN];
void DFSRoot(int now,int last)
{
size[now]=; maxx[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !visit[edge[i].to])
{
DFSRoot(edge[i].to,now);
size[now]+=size[edge[i].to];
maxx[now]=max(maxx[now],size[edge[i].to]);
}
maxx[now]=max(maxx[now],Sz-size[now]);
if (maxx[now]<maxx[root]) root=now;
}
void Get(int x,int last,int Dis)
{
D[++dfn]=Dis; L[dfn]=pl,R[dfn]=pr;
for (int i=head[x]; i; i=edge[i].next)
if (!visit[edge[i].to] && edge[i].to!=last)
Get(edge[i].to,x,Dis+edge[i].val);
}
void Divide(int x)
{
visit[x]=;
pl=pr=++dfn;
for (int i=head[x]; i; i=edge[i].next)
if (!visit[edge[i].to]) Get(edge[i].to,x,edge[i].val),pr=dfn;
for (int i=head[x]; i; i=edge[i].next)
if (!visit[edge[i].to])
{
Sz=size[edge[i].to]; root=;
DFSRoot(edge[i].to,x);
Divide(root);
}
}
int log2[MAXM],dp[][MAXM];
int Max(int x,int y) {return D[x]>D[y]? x:y;}
void ST()
{
log2[]=-;
for (int i=; i<=N; i++)
if (i&(i-)) log2[i]=log2[i-]; else log2[i]=log2[i-]+;
for (int i=; i<=dfn; i++) dp[][i]=i;
for (int j=; (<<j)<=dfn; j++)
for (int i=; i+(<<j)-<=dfn; i++)
dp[j][i]=Max(dp[j-][i],dp[j-][i+(<<j-)]);
}
inline int RMQ(int l,int r)
{
int tmp=log2[r-l+];
return Max(dp[tmp][l],dp[tmp][r-(<<tmp)+]);
}
struct HeapNode
{
int ip,L,R,pos;
HeapNode (int ip=,int L=,int R=,int pos=)
: ip(ip),L(L),R(R),pos(pos) {}
bool operator < (const HeapNode & A) const
{return D[ip]+D[pos]<D[A.ip]+D[A.pos];}
};
priority_queue<HeapNode>heap;
int main()
{
N=read(),M=read();
for (int x,y,z,i=; i<=N-; i++) x=read(),y=read(),z=read(),InsertEdge(x,y,z);
maxx[root=]=Sz=N;
DFSRoot(,);
Divide(root);
ST();
for (int i=; i<=dfn; i++)
heap.push( HeapNode(i,L[i],R[i],RMQ(L[i],R[i])) );
while (M--)
{
HeapNode now=heap.top(); heap.pop();
printf("%d\n",D[now.ip]+D[now.pos]);
HeapNode ls=now; ls.R=now.pos-;
if (ls.R>=ls.L) ls.pos=RMQ(ls.L,ls.R),heap.push(ls);
HeapNode rs=now; rs.L=now.pos+;
if (rs.R>=rs.L) rs.pos=RMQ(rs.L,rs.R),heap.push(rs);
}
return ;
}
一天前刚写超级钢琴,写起来就非常顺畅了
【BZOJ-3784】树上的路径 点分治 + ST + 堆的更多相关文章
- BZOJ.3784.树上的路径(点分治 贪心 堆)
BZOJ \(Description\) 给定一棵\(n\)个点的带权树,求树上\(\frac{n\times(n-1)}{2}\)条路径中,长度最大的\(m\)条路径的长度. \(n\leq5000 ...
- BZOJ 3784: 树上的路径 点分治+二分+set
很容易想出二分这个思路,但是要想办法去掉一个 $log$. 没错,空间换时间. 双指针的部分错了好几次~ Code: #include <set> #include <queue&g ...
- bzoj 3784: 树上的路径 堆维护第k大
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 88 Solved: 27[Submit][Status][Discuss] ...
- bzoj 3784: 树上的路径【点分治+st表+堆】
参考:https://www.cnblogs.com/CQzhangyu/p/7071477.html 神奇的点分治序(或者叫点剖?).就是把点分治扫过的点依次放进队列里,然后发现,对于每一棵树摊到序 ...
- BZOJ 3784: 树上的路径
Description 问一棵树上前 \(k\) 大路径的边权. Sol 边分治. 非常感谢数据没有菊花图. 为了写写边分治试试然后就开了这道题. 边分治非常好想,选一条重边,分成两部分,然后分别求最 ...
- 【BZOJ3784】树上的路径 点分治序+ST表
[BZOJ3784]树上的路径 Description 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a< ...
- BZOJ 1316: 树上的询问( 点分治 + 平衡树 )
直接点分治, 用平衡树(set就行了...)维护. -------------------------------------------------------------------------- ...
- BZOJ 3697: 采药人的路径 [点分治] [我想上化学课]
传送门 题意: 路径有$-1,1$两种权值,求有多少路径满足权值和为$0$且有一个点将路径分成权值和为$0$的两段 第四节课本来想去上化学,然后快上课了这道题还没调出来.....可恶我想上化学 昨天两 ...
- BZOJ 3697: 采药人的路径 点分治
好久不做点分治的题了,正好在联赛之前抓紧复习一下. 先把边权为 $0$ 的置为 $-1$.定义几个状态:$f[dis][0/1],g[dis][0/1]$ 其中 $f$ 代表在当前遍历的子树内的答案. ...
随机推荐
- Openvpn 公网访问内网
对于需要从公网访问内网的情况, 需要做如下配置 从公网到内网 除了设置net.ipv4.ip_forward = 1 以外, 还需要设置iptables, 增加两行forward # Generate ...
- js Dialog 去掉右上角的X关闭功能
用到 dialog弹出框时,不想要右上角的X 关闭功能,只是做个提示信息显示,下面是具体的去掉方法,大家可以参考下 再用到 dialog弹出框时,不想要右上角的X 关闭功能,只是做个提示信息显示. 在 ...
- NOIP2016提高组解题报告
NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合
- Delete Node in a Linked List
Write a function to delete a node (except the tail) in a singly linked list, given only access to th ...
- img加载在IE11,chrome,FF下的不同
IE11 img.complete 得不到img的大小,会使用img.onload chrome,ff:img.complete 得不到img的大小,会使用自己创建的img加载方法
- web学习第一章
web学习第一章 我是大概9月10日开始走上IT之路的,一开始学习了小段时间的自动化办公软件, 昨天我开始学习客户端网页编程,我了解什么是WEB,一些比较老古董的计算模式和发展历史,印象最让我深刻 ...
- easyui layout 折叠后显示标题
(function($){ var buttonDir = {north:'down',south:'up',east:'left',west:'right'}; $.extend($.fn.layo ...
- 通过源码分析MyBatis的缓存
前方高能! 本文内容有点多,通过实际测试例子+源码分析的方式解剖MyBatis缓存的概念,对这方面有兴趣的小伙伴请继续看下去~ MyBatis缓存介绍 首先看一段wiki上关于MyBatis缓存的介绍 ...
- fdisk分区硬盘并shell脚本自动化
最近工作需要用到对硬盘进行shell脚本自动化分区和mount的操作,google了一些资料,下面做个总结. 如果硬盘没有进行分区(逻辑分区或者扩展分区,关于两者概念,自行google),我们将无法将 ...
- 跨浏览器事件EventUtil
<div style="width: 150px; height: 150px; padding: 25px; border:1px solid blue; " id=&qu ...