bzoj 3784: 树上的路径 点分治+RMQ+堆

题意

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

分析

这题有一种做法是先二分答案点分治,求出距离值的下界后再点分治一次把全部距离值找到。这样做的话由于点分治的复杂度是O(nlog^2n)的,加上二分的一个log就会超时。于是我们可以先用vector把每个分治树的距离值排好序放进去,这样总的复杂度就是O(nlog^2)了。
还有一种做法就是,先把点分治序列做出来,也就是每到一棵分治树就把这棵树的dfs序放进序列中。这样的话每个点能取到的位置就是两段区间,那么我们就可以用堆维护四元组(id,l,r,m)表示第id个点,它能取的区间是[l,r]且这里面的最大值在位置m。每次从堆中取出最大值后我们就把该区间分裂成[l,m-1]和[m+1,r]再扔进堆里面即可。查询最大值可以用ST表。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#define mp(x,y) make_pair(x,y)
using namespace std;

const int N=50005;
const int K=20;

int n,m,size[N],cnt,last[N],f[N],root,sum,tot,bin[23],rmq[N*K][23],now,a[N*K],b[N],lef[N*K],rig[N*K],lg[N*K];
bool vis[N];
struct edge{
  int to,next,w;}e[N*2];
struct data
{
    int id,l,r,m;
    bool operator < (const data &d) const {
  return a[id]+a[m]<a[d.id]+a[d.m];};
};
vector<data> vec;
priority_queue<data> que;

int read()
{
    int
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值