Description

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

Input

第一行包含两个正整数\(N,M\)。

下面\(N − 1\)行,每行三个正整数\(a, b, c (a, b \le N, c \le 10,000)\),表示结点\(a\)和结点\(b\)间有一条权值为\(c\)的边相连。

Output

共\(M\)行,每行一个正整数,第\(i\)行表示排在第\(i\)个的距离值。

Sample Input

5 10

1 2 1

1 3 2

2 4 3

2 5 4

Sample Output

7

7

6

5

4

4

3

3

2

1

Hint

\(N \le 50000,M \le min(\frac{N(N-1)}{2},30,000)\)

点分治+K路归并。由于树上的每条路径必定经过一个重心,在进行点分治时我们可以枚举到所有的路径。将重心到每个点的距离按dfs序插入数组(可以把每次分治的结果都插入数组中,数组开\(O(NlogN)\))中。由于保证枚举的两个点不在一棵子数中,每个点对应的链在dfs数组中一定是段连续的区间,故可以采用超级钢琴的做法。代码如下:

#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<set>
#include<vector>
using namespace std; #define maxn (100010)
int N,M,next[maxn],toit[maxn],len[maxn],side[maxn],L,R,f[20][maxn*10],bit[maxn*10];
int cnt = 1,num,size[maxn],large[maxn],dis[maxn*10],best; bool vis[maxn];
struct node
{
int pos,l,r,mx,key;
friend inline bool operator <(const node &a,const node &b) { return a.key > b.key; }
};
vector <node> vec; multiset <node> S; inline void add(int a,int b,int c) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; len[cnt] = c; }
inline void ins(int a,int b,int c) { add(a,b,c); add(b,a,c); } inline void getroot(int now,int fa,int rest)
{
size[now] = 1; large[now] = 0;
for (int i = side[now];i;i = next[i])
{
if (toit[i] == fa||vis[toit[i]]) continue;
getroot(toit[i],now,rest);
size[now] += size[toit[i]];
large[now] = max(large[now],size[toit[i]]);
}
large[now] = max(large[now],rest-size[now]);
if (large[now] < large[best]) best = now;
}
inline int find_root(int now,int rest) { best = 0; getroot(now,0,rest); return best; } inline void dfs(int now,int fa,int d)
{
dis[++cnt] = d; vec.push_back((node){cnt,L,R,0,0});
for (int i = side[now];i;i = next[i])
if (toit[i] != fa&&!vis[toit[i]])
dfs(toit[i],now,d+len[i]);
} inline void cut(int now)
{
vis[now] = true; L = R = ++cnt;
for (int i = side[now];i;i = next[i])
{
if (vis[toit[i]]) continue;
dfs(toit[i],now,len[i]); R = cnt;
}
for (int i = side[now];i;i = next[i])
if (!vis[toit[i]]) cut(find_root(toit[i],size[toit[i]]));
} inline int query(int l,int r)
{
int len = r-l+1,lg = bit[len];
if (dis[f[lg][l]] > dis[f[lg][r-(1<<lg)+1]]) return f[lg][l];
else return f[lg][r-(1<<lg)+1];
} int main()
{
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
scanf("%d %d",&N,&M);
for (int i = 1,a,b,c;i < N;++i) scanf("%d %d %d",&a,&b,&c),ins(a,b,c);
large[0] = 1<<30; cnt = 0; cut(find_root(1,N));
for (int i = 1;(1 << i) <= (cnt<<1);++i)
for (int j = (1<<(i-1));j <= (1<<i)-1&&j <= cnt;++j) bit[j] = i-1;
for (int i = 1;i <= cnt;++i) f[0][i] = i;
for (int i = 1;i <= bit[cnt];++i)
for (int j = 1;j+(1<<i)-1 <= cnt;++j)
{
if (dis[f[i-1][j]] > dis[f[i-1][j+(1<<(i-1))]]) f[i][j] = f[i-1][j];
else f[i][j] = f[i-1][j+(1<<(i-1))];
}
int nn = vec.size();
for (int i = 0;i < nn;++i)
{
node tmp = vec[i];
tmp.mx = query(tmp.l,tmp.r); tmp.key = dis[tmp.pos]+dis[tmp.mx];
S.insert(tmp);
}
for (int i = 1;i <= M;++i)
{
node now = *S.begin(); S.erase(S.begin());
printf("%d\n",now.key);
if (now.mx > now.l)
{
node tmp; tmp = now;
tmp.mx = query(tmp.l,tmp.mx-1);
tmp.key = dis[tmp.mx]+dis[tmp.pos];
tmp.r = now.mx-1; S.insert(tmp);
}
if (now.mx < now.r)
{
node tmp; tmp = now;
tmp.mx = query(tmp.mx+1,tmp.r);
tmp.key = dis[tmp.mx]+dis[tmp.pos];
tmp.l = now.mx+1; S.insert(tmp);
}
}
fclose(stdin); fclose(stdout);
return 0;
}

CTSC模拟题 树上的路径的更多相关文章

  1. 某模拟赛C题 树上路径统计 (点分治)

    题意 给定一棵有n个节点的无根树,树上的每个点有一个非负整数点权.定义一条路径的价值为路径上的点权和-路径上的点权最大值. 给定参数P,我!=们想知道,有多少不同的树上简单路径,满足它的价值恰好是P的 ...

  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. 全国信息学奥林匹克联赛 ( NOIP2014) 复赛 模拟题 Day1 长乐一中

    题目名称 正确答案  序列问题 长途旅行 英文名称 answer sequence travel 输入文件名 answer.in sequence.in travel.in 输出文件名 answer. ...

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

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

  6. ACdreamoj(1105)模拟题

    题意:射一次激光最多能够攻击到几个敌人(因为激光非常强大,能够在击中敌人后穿过它,而瑶瑶自己的坦克因为有特殊装置,所以不会被激光击中.激光也会直接穿过它) . 表示此处为空地 * 表示此处为障碍(激光 ...

  7. NOIP模拟题 2017.7.3 - 模拟 - 贪心 - 记忆化搜索

    直接暴力模拟,注意判数据结构为空时的取出操作. Code #include<iostream> #include<cstdio> #include<ctime> # ...

  8. NOIP模拟题汇总(加厚版)

    \(NOIP\)模拟题汇总(加厚版) T1 string 描述 有一个仅由 '0' 和 '1' 组成的字符串 \(A\),可以对其执行下列两个操作: 删除 \(A\)中的第一个字符: 若 \(A\)中 ...

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

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

随机推荐

  1. 传输层:TCP UDP SCTP

    总图 虽然协议族被称为“TCP/IP”,但除了TCP和IP这两个主要协议外,还有许多其他成员.图2-1展示了这些协议的概况. 图2-1中同时展示了IPV4和IPV6.从右向左看该图,最右边的5个网络应 ...

  2. jwplayer 源代码重新编译

    由于原来下载的jwplaery播放器中带有官方的播放统计信息,需要从官方加载统计js脚本,影响播放器加载速度,因此从官方github站点上下载播放器进行重新编译操作,现记录过程如下. 下载最新的jwp ...

  3. python 入门1

    python的历史 Python是一种解释型.面向对象.动态数据类型的高级程序设计语言. Python由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年. 像Per ...

  4. mysql连接错误:Cannot get hostname for your address

    问题 环境:win7 + 64Bit + 本地mysql5.6 问题:navicat连接本地mysql数据库,提示“Cannot get hostname for your address”,但是连接 ...

  5. Nico Game Studio 3.地图纹理编辑 物体皮肤编辑

    完成功能: 1.地图纹理编辑功能. 图层编辑,添加/删除纹理,地图编辑.网格绘制.

  6. scope的参数范围

    Default -- 显示当前文件夹下的:文件和文件夹 FilesOnly--显示当前文件夹下的:文件 Recursive --显示当前文件夹下的:所有文件,包括子文件夹中的文件 RecursiveA ...

  7. oracle 定位热块和热链的方法

    定位热链的方法 declare        v_num number;begin        for i in 1..1000000        loop                sele ...

  8. ios framework通用库的制作

    这篇文章是在史上最完整的iOS DIY framework 详细教程(一)的基础上加以修改 1.新建一个静态库工程: 2:取自己喜欢的名字: 3.删除向导所生成工程中的 Target: 3.删除Tes ...

  9. 逻辑回归:使用SGD(Stochastic Gradient Descent)进行大规模机器学习

    Mahout学习算法训练模型 mahout提供了许多分类算法,但许多被设计来处理非常大的数据集,因此可能会有点麻烦.另一方面,有些很容易上手,因为,虽然依然可扩展性,它们具有低开销小的数据集.这样一个 ...

  10. 协程的作用 Python

    1.协程的含义和实现 协程是单进程单线程的超越函数的调度机制,它通过一定的调度手段进行调度. (Python使用generator机制,greenlet使用汇编控制对程序指向来实现). 2.协程有什么 ...