BZOJ 3784: 树上的路径(点分治+ST表+堆堆堆)

题目喵述

权限门

题目大意:给一棵树,有N个点,有边权。所有无向路径中,请你输出前M大的。

N<=50000
M<=Min(300000,n*(n-1) /2)


思路

树上超级钢琴。(拖延症的结果就是现在才写这题)

学了一种点分治的套路,在做点分治的时候求出整棵树的dfs序。可以发现,每个点在dfs序列中出现不超过log次。我们不妨称其为点分治序。

然后类比超级钢琴,将序列转换到树上。强制路径过分治中心,然后每一条路径的长度对应Dis[x]+Dis[y]。其中x和y要求在分治中心的不同子树内。这里我们不可以直接做然后减什么的,有一种方便的技巧就是枚举儿子,每个儿子dfs一次。记录每个点为路径尾能取到的头的区间[L,R]。

接下来,直接在点分治序上做ST表,丢进大根堆里然后分裂区间即可,这里跟在序列上几乎一样。

时间复杂度是两个log的。

还有一种二分的做法,加上每次点分治总共有3个log,是过不了的,但是先点分治一次,排好序并记下来,然后就只有两个log了,也是很强的。


代码

#include <bits/stdc++.h>
#define maxn 800010
#define Lg 20

using namespace std;

int n, m, cur = -1;
struct List{
    List *next;
    int obj, len;
}*head[maxn], Edg[maxn<<1];

void Addedge(int a, int b, int c){
    Edg[++cur].next = head[a];
    Edg[cur].obj = b;
    Edg[cur].len = c;
    head[a] = Edg+cur;
}

bool Vis[maxn];
int Root, Sum, Dfn;
int son[maxn], siz[maxn], fa[maxn];
int T[maxn], f[Lg][maxn], g[Lg][maxn];
int tL[maxn], tR[maxn], Dis[maxn];

struct World{
    int x, y, l, r;
    World() {}
    World(
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值