树上的路径

【问题描述】

给定一个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. HTML5<aside>元素

    HTML5<aside>元素用来定义页面文档中主区域内容之外的内容,但之外的内容是与主区域内容相关的. 实例: <article> <h1>这个页面是我开始用htm ...

  2. c++ 创建路径方法

    linux.unix平台 #include "stdio.h" #include "stdlib.h" #include <sys/types.h> ...

  3. c++ 用指针操作数组

    #include <iostream> using namespace std; const int Max = 5; double * fill_array(double * first ...

  4. C++ 学习笔记(一) cout 与printf 的不同之处

    作为一个嵌入式开发的猿,使用打印调试程序是必不可少的,拿到新的项目第一件事就是捣鼓打印.这次也不例外有打印才有耍下去的底气.在之前零零碎碎的C++学习中,还是一边学一边做项目的状态下能用printf解 ...

  5. mariadb多源主从复制错误跳过.md

    mysql 的主从错误跳过和mariadb的多源主从复制错误跳过操作不同,请注意: 更改会话的default_master_connection变量 STOP SLAVE 'slave_account ...

  6. 201621123080《Java程序设计》第三周学习总结

    Week03-面向对象入门 1. 本周学习总结 2. 书面作业 1.以面向对象方式改造数据结构作业'有理数'(重点) 1.1 截图你主要代码(需要在程序中出现你的学号和姓名)并粘贴程序的git地址. ...

  7. k8s调度的预选策略及优选函数

    scheduler调度过程:    Predicate(预选)-->Priority(优选)-->Select(选定)调度方式:    1.节点亲和性调度(NodeAffinity)使用n ...

  8. js替换函数用法

    定义和用法 replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串. 语法 stringObject.replace(regexp/substr,replac ...

  9. 图解一致性协议2PC和3PC

    原图地址:https://www.processon.com/diagraming/5b89f6ace4b0d4d65bf10786

  10. token验证机制

    最近在vue-cli项目实现登录的过程中用到了token验证,在此总结如下 1. 登录时,客户端通过用户名与密码请求登录 2. 服务端收到请求去验证用户名与密码 3. 验证通过,服务端会签发一个Tok ...