树上的路径

【问题描述】

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

【输入格式】

第一行两个正整数N,M
下面N-1行,每行三个正整数a,b,c(a,b<=N,C<=10000)。表示结点a到结点b有一条权值为c的边。
【输出格式】
共M行,如题所述.

【样例输入】

5 10
1 2 1
1 3 2
2 4 3
2 5 4

【样例输出】

7
7
6
5
4
4
3
3
2
1
【数据范围】

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


题解:

考虑将点分治时访问的点的顺序作为一个序列

每个位置都有其对应的区间(指向这个位置所在重心树访问的前面所有子树,那么这就代表了这个位置对应的点出发经过这个重心的所有路径)

那么原问题转化为了BZOJ 2006 超级钢琴的问题

 #include<cmath>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf = ;
const int logn = ;
const int logs = ;
const int maxn = 5e4 + ;
const int maxm = maxn << ;
const int maxs = maxn * logn + ;
inline void Scan(int &x)
{
char c;
bool o = false;
while(!isdigit(c = getchar())) o = (c != '-') ? o : true;
x = c - '';
while(isdigit(c = getchar())) x = x * + c - '';
if(o) x = -x;
}
int tot, nex[maxm], ver[maxm], fir[maxn], val[maxm];
inline void Ins(int x, int y, int z)
{
nex[++tot] = fir[x];
fir[x] = tot;
ver[tot] = y;
val[tot] = z;
}
int sum, root;
int size[maxn], heavy[maxn];
bool vis[maxn];
void Getroot(int u, int f)
{
heavy[u] = ;
size[u] = ;
for(int i = fir[u]; i; i = nex[i])
{
int v = ver[i];
if(v == f || vis[v]) continue;
Getroot(v, u);
size[u] += size[v];
heavy[u] = max(heavy[u], size[v]);
}
heavy[u] = max(heavy[u], sum - size[u]);
if(heavy[u] < heavy[root]) root = u;
}
struct couple
{
int l, r;
};
couple c[maxs];
int num, l, r;
int dis[maxn], len[maxs];
int big[logs][maxs];
void Getdis(int u, int f)
{
len[++num] = dis[u], big[][num] = num;
c[num] = (couple) {l, r};
for(int i = fir[u]; i; i = nex[i])
{
int v = ver[i];
if(v == f || vis[v]) continue;
dis[v] = dis[u] + val[i];
Getdis(v, u);
}
}
void Div(int u)
{
root = ;
Getroot(u, );
l = r = ++num;
len[num] = , big[][num] = num;
vis[root] = true;
for(int i = fir[root]; i; i = nex[i])
{
int v = ver[i];
if(vis[v]) continue;
dis[v] = val[i];
Getdis(v, root);
r = num;
}
for(int i = fir[root]; i; i = nex[i])
{
int v = ver[i];
if(vis[v]) continue;
sum = size[v];
Div(v);
}
}
inline int Max(int a, int b)
{
return (len[a] > len[b]) ? a : b;
}
int bin[logs], lg[maxs];
inline void Rmq()
{
int lgn = log2(num);
bin[] = ;
for(int i = ; i <= lgn; ++i) bin[i] = bin[i - ] << , lg[bin[i]] = ;
for(int i = ; i <= num; ++i) lg[i] += lg[i - ];
for(int k = ; k <= lgn; ++k)
for(int i = ; i <= num; ++i)
{
if(i + bin[k] - > num) continue;
int j = i + bin[k - ];
big[k][i] = Max(big[k - ][i], big[k - ][j]);
}
}
inline int Query(int l, int r)
{
if(l > r) return -;
int len = lg[r - l + ];
return Max(big[len][l], big[len][r - bin[len] + ]);
}
int n, m;
struct interval
{
int l, r, a, b, v;
};
inline bool operator < (interval a, interval b)
{
return a.v < b.v;
}
priority_queue <interval> q;
int main()
{
Scan(n), Scan(m);
int a, b;
for(int i = ; i < n; ++i)
{
int c;
Scan(a), Scan(b), Scan(c);
Ins(a, b, c), Ins(b, a, c);
}
sum = n;
root = ;
heavy[] = inf;
Div();
Rmq();
int x;
for(int i = ; i <= num; ++i)
{
a = c[i].l, b = c[i].r;
if(a)
{
x = Query(a, b);
q.push((interval) {a, b, i, x, len[i] + len[x]});
}
}
int u, v;
interval s;
while(m--)
{
s = q.top(), q.pop();
u = Query(s.l, s.b - );
v = Query(s.b + , s.r);
if(u > ) q.push((interval) {s.l, s.b - , s.a, u, len[u] + len[s.a]});
if(v > ) q.push((interval) {s.b + , s.r, s.a, v, len[v] + len[s.a]});
printf("%d\n", s.v);
}
}

树上的路径 BZOJ 3784的更多相关文章

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

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

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

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

  3. codevs 2756树上的路径

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

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

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

  5. Codevs 2756 树上的路径

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

  6. BZOJ 3784: 树上的路径

    Description 问一棵树上前 \(k\) 大路径的边权. Sol 边分治. 非常感谢数据没有菊花图. 为了写写边分治试试然后就开了这道题. 边分治非常好想,选一条重边,分成两部分,然后分别求最 ...

  7. BZOJ.3784.树上的路径(点分治 贪心 堆)

    BZOJ \(Description\) 给定一棵\(n\)个点的带权树,求树上\(\frac{n\times(n-1)}{2}\)条路径中,长度最大的\(m\)条路径的长度. \(n\leq5000 ...

  8. bzoj 3784: 树上的路径【点分治+st表+堆】

    参考:https://www.cnblogs.com/CQzhangyu/p/7071477.html 神奇的点分治序(或者叫点剖?).就是把点分治扫过的点依次放进队列里,然后发现,对于每一棵树摊到序 ...

  9. BZOJ 3784: 树上的路径 点分治+二分+set

    很容易想出二分这个思路,但是要想办法去掉一个 $log$. 没错,空间换时间. 双指针的部分错了好几次~ Code: #include <set> #include <queue&g ...

随机推荐

  1. oracle 快速复制一张表,并在此创建索引,日志及并行度

    复制表结构及其数据 create table table_name_new as select * from table_name_old 只复制表结构 create table table_name ...

  2. 使用lua实现Spine动画的预加载

    创建spine动画有两种方法,分别是createwithfile和createwithdata. createWithFile是通过加载动作数据马上进行创建,如果spine动画中的json文件大小超过 ...

  3. 53. Maximum Subarray@python

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

  4. NOIP2013 乌龟棋

    描述 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物. 乌龟棋的棋盘是一行N个格子,每个格子上一个分数(非负整数).棋盘第1格是唯一的起点,第N格是终点,游戏要求玩家控制一个乌龟棋子从起点出发走到终点 ...

  5. 【线段树合并】bzoj3545: [ONTAK2010]Peaks

    1A还行 Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问, ...

  6. Ubuntu 下安装mysqlclient报错

    pip3 install mysqlclient 报错信息 问题描述: Complete output from command python setup.py egg_info: /bin/sh: ...

  7. IDEA入门学习笔记1:资料收集

    IDEA2018软件下载 :https://mp.weixin.qq.com/s?__biz=MzIwMjE1MjMyMw==&mid=2650200056&idx=1&sn= ...

  8. python中的内建函数

    本文用作记录python中的内建函数及其功能,本文内容随时补充. 完整的内建函数及其说明参考官方文档:    https://docs.python.org/3.5/library/functions ...

  9. Linux扩增卷组、逻辑卷以及缩减逻辑卷

    今天我们将了解怎样来扩展卷组,扩展和缩减逻辑卷.在这里,我们可以缩减或者扩展逻辑卷管理(LVM)中的分区,LVM也可称之为弹性卷文件系统. 前置需求使用LVM创建弹性磁盘存储——第一部分 什么时候我们 ...

  10. 2018 Multi-University Training Contest 1 Distinct Values(set)

    题意: t组数据,每组数据给定n,m, 表示有m个约束,每个约束包含 x,y ,代表区间 [x, y] 里的数字不能相同. 让你用所有的正整数构成一个长度为 n 的区间,使得这个区间元素顺序的字典序最 ...