【BZOJ3784】树上的路径 点分治序+ST表
【BZOJ3784】树上的路径
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 )
题解:“总有那么一种序列,可以满足你某道题的所需的一切性质~”
没错,听说过DFS序吗,听说过BFS序吗,如果你都听说过,那么你听说过点分治序吗?
没错,点分治序,顾名思义,就是点分治时扫过的序列(包括每次找到的重心和从重心出发依次DFS过的所有子树),它的长度是nlogn的。那么这样一个序列有什么性质呢?
如果我们已经确定了一个分治中心和它的子树中的一条链,我们想找到这个分治中心的另一条链(亦或是这个分治中心本身)和它来组成一条路径,那么这些路径的端点在什么位置呢?没错,他们在点分治序上正好是一段连续的序列!并且根据点分治的原理,通过这样我们可以找到树上所有的路径。
那么问题就变成了:给你一个序列,你每次可以从中选取一个二元组(a,b),其中对于每一个b,可以与它搭配的a都在一段给定的区间里。每个二元组的值是a的权值+b的权值,求前k大的二元组。这不就是BZOJ2006超级钢琴吗?直接ST表就好了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <utility>
#include <queue>
#define mp(A,B,C,D) make_pair(make_pair(A,B),make_pair(C,D))
using namespace std;
const int maxn=50010;
typedef pair<int,int> pii;
int n,m,cnt,maxx,tot,root,nm;
int sm[800010][20],to[maxn<<1],next[maxn<<1],val[maxn<<1],head[maxn],siz[maxn];
int lp[800010],rp[800010],v[800010],vis[maxn],Log[800010];
priority_queue<pair<pii,pii> > pq;
int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
int ms(int a,int b)
{
return v[a]>v[b]?a:b;
}
void add(int a,int b,int c)
{
to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
}
void getr(int x,int fa)
{
siz[x]=1;
int i,mx=0;
for(i=head[x];i!=-1;i=next[i])
{
if(vis[to[i]]||to[i]==fa) continue;
getr(to[i],x),siz[x]+=siz[to[i]],mx=max(mx,siz[to[i]]);
}
if(maxx>max(mx,tot-siz[x])) root=x,maxx=max(mx,tot-siz[x]);
}
void getd(int x,int fa,int dep)
{
v[++nm]=dep,lp[nm]=lp[nm-1],rp[nm]=rp[nm]?rp[nm]:rp[nm-1];
for(int i=head[x];i!=-1;i=next[i])
{
if(vis[to[i]]||to[i]==fa) continue;
getd(to[i],x,dep+val[i]);
}
}
void dfs(int x)
{
vis[x]=1;
int i;
v[++nm]=0,lp[nm]=nm,rp[nm]=nm-1;
for(i=head[x];i!=-1;i=next[i])
{
if(vis[to[i]]) continue;
rp[nm+1]=nm,getd(to[i],x,val[i]);
}
for(i=head[x];i!=-1;i=next[i])
{
if(vis[to[i]]) continue;
tot=siz[to[i]],maxx=1<<30,getr(to[i],x),dfs(root);
}
}
int query(int a,int b)
{
if(a>b) return 0;
int k=Log[b-a+1];
return ms(sm[a][k],sm[b-(1<<k)+1][k]);
}
int main()
{
n=rd(),m=rd();
int i,j,a,b,c,d,x,y;
memset(head,-1,sizeof(head));
for(i=1;i<n;i++) a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
tot=n,maxx=1<<30,getr(1,0),dfs(root);
for(i=1;i<=nm;i++) sm[i][0]=i;
for(i=2;i<=nm;i++) Log[i]=Log[i>>1]+1;
for(j=1;(1<<j)<nm;j++)
for(i=1;i+(1<<j)-1<=nm;i++)
sm[i][j]=ms(sm[i][j-1],sm[i+(1<<j-1)][j-1]);
for(i=1;i<=nm;i++)
{
if(lp[i]>rp[i]) continue;
pq.push(mp(v[i]+v[query(lp[i],rp[i])],i,lp[i],rp[i]));
}
for(i=1;i<=m;i++)
{
pii t1=pq.top().first,t2=pq.top().second;
pq.pop();
printf("%d\n",t1.first),x=t1.second,a=t2.first,b=t2.second,y=query(a,b);
c=query(a,y-1),d=query(y+1,b);
if(c) pq.push(mp(v[x]+v[c],x,a,y-1));
if(d) pq.push(mp(v[x]+v[d],x,y+1,b));
}
return 0;
}
【BZOJ3784】树上的路径 点分治序+ST表的更多相关文章
- 【BZOJ-3784】树上的路径 点分治 + ST + 堆
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 462 Solved: 153[Submit][Status][Discuss ...
- 2019.01.20 bzoj3784: 树上的路径(二分答案+点分治)
传送门 点分治好题. 题意简述:给一棵带边权的树,问所有路径中前mmm大的.m≤300000m\le300000m≤300000 思路: 网上有题解写了可以通过什么点分治序转化成超级钢琴那道题的做法蒟 ...
- BZOJ.3784.树上的路径(点分治 贪心 堆)
BZOJ \(Description\) 给定一棵\(n\)个点的带权树,求树上\(\frac{n\times(n-1)}{2}\)条路径中,长度最大的\(m\)条路径的长度. \(n\leq5000 ...
- BZOJ3784树上的路径
题目描述 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距离从大到小排序, ...
- 【BZOJ3611】[Heoi2014]大工程 欧拉序+ST表+单调栈
[BZOJ3611][Heoi2014]大工程 Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶 ...
- BZOJ3784 : 树上的路径
树的点分治,在分治的时候将所有点到根的距离依次放入一个数组q中. 对于一棵子树里的点,合法的路径一定是q[L]..q[R]的某个数加上自己到重心的距离. 定义五元组(v,l,m,r,w),表示当前路径 ...
- BZOJ 3784: 树上的路径 点分治+二分+set
很容易想出二分这个思路,但是要想办法去掉一个 $log$. 没错,空间换时间. 双指针的部分错了好几次~ Code: #include <set> #include <queue&g ...
- 51Nod1766 树上的最远点对 ST表 LCA 线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1766.html 题目传送门 - 51Nod1766 题意 n个点被n-1条边连接成了一颗树,给出a~ ...
- [51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树)
[51nod 1766]树上的最远点对 (树的直径+ST表求lca+线段树) 题面 给出一棵N个点的树,Q次询问一点编号在区间[l1,r1]内,另一点编号在区间[l2,r2]内的所有点对距离最大值.\ ...
随机推荐
- Linux内核锁与中断处理
Linux内核锁 在Linux内核里面,一般采用了如下几种锁的机制,来保证多线程的同步与互斥: (1)原子操作 atomic_t v: void atomic_set(atomic_t *v, int ...
- opengl中VAO,VBO,IBO用法小结【转】
http://cowboy.1988.blog.163.com/blog/static/751057982014380251300/ opengl中VAO,VBO,IBO用法小结 这三个玩意全面取代旧 ...
- 一个例子理解Predicate、Consumer和Stream
一个需求: 把年龄大于20的学生的信息打印出来. 面向对象编程 public class Student { private String name; private int age; private ...
- 介绍下Shell中的${}、##和%%使用范例
假设定义了一个变量为:代码如下:file=/dir1/dir2/dir3/my.file.txt可以用${ }分别替换得到不同的值:${file#*/}:删掉第一个 / 及其左边的字符串:dir1/d ...
- Binder与interface
在Interface中,asBinder函数涌来将服务类接口类型转换为IBinder类型: 相反的,asInterface函数用来将Ibinder类型转换为服务接口类型
- python可hash 不可hash类型
不可变类型是可hash #tuple str freezeset 可变类型是不可hash ##list set
- 王立平--scard0与scard1分别指的是什么?以及路径获取
一般是: scard0:指系统内部存储 scard1:指外插的sd卡 也有特例.. 分别获取路径的方法: package com.main; import java.lang.reflect.Meth ...
- 网络编程 TCP学习
上传txt文本 通过socket向服务端发送数据 然后用serversocket 接收socket 通过流读取数据保存 服务端在发送确认信息并在client输出 client import java. ...
- iOS项目开发实战——使用同步请求获取网页源码
网络请求一般分为同步请求和异步请求,同步请求假设訪问时间过长,会造成界面卡死状态,用户体验不是非常好.可是请求速度较快的话,也能够考虑使用同步訪问.如今先来学习同步訪问. (1)在viewDidLoa ...
- 程序猿的量化交易之路(24)--Cointrader之RemoteEvent远程事件实体(11)
转载需注明出处:http://blog.csdn.net/minimicall,http://cloudtrader.top/ 在量化交易系统中.有些事件是远端传来的,比方股票的价格数据等.所以,在这 ...