第三道点分治。

首先找到黄学长的题解,他叫我参考XXX的题解,但已经没有了,然后找到另一个博客的简略题解,没看懂,最后看了一个晚上黄学长代码,写出来然后,写暴力都拍了小数据,但居然超时,。。。。然后改了一下存图方式,还是T,读入优化,还是T,最后把BFS找重心改成DFS找重心后才过的(因为DFS只遍历一遍,但BFS要多遍历几遍)。

————————————————————以上是废话————————————————————————

题目:给定一个边带权的无根树,求长度排名为前m的路径的长度。

首先,肯定不能求出所有路径来排序,因为n很大。但我们要求前m大的路径,容易想到,我们先求出极大路径,求出最大,删掉它,然后再加上新产生的极大路径,但我们怎么定义“极大路径”呢,是长度不能再延伸的路径吗,可以发现这样选择,求新产生的极大路径会出现问题。

那这道题是怎么做的呢?在点分治时,每一个重心会对应很多棵子树,先对当前重心代表的那一棵树进行一次DFS,幷保存每个点的DFS序,以及DFS序中每个位置对应点到当前重心的距离,并且我们为每个点保存一个DFS序的区间,该区间包含根和包含它的子树的左边的子树(不包含它所在的子树),这样元素(lf,rg,x)代表dfs序上第x个点与区间[lf,rg]上代表的点的路径,即它代表一些路径而不是一条。并且可以证明每一条路径属于且仅属于其中一个元素。

每个元素代表的路径中存在最长的路径,以该路径的长度为关键字将元素放进堆中,每次找到后,将那个元素分成两个。。。。。。。

。。。。。。。。。。

 /**************************************************************
Problem: 3784
User: idy002
Language: C++
Result: Accepted
Time:6940 ms
Memory:208820 kb
****************************************************************/ #include <cstdio>
#include <cctype>
#include <vector>
#include <queue>
#define max(a,b) ((a)>(b)?(a):(b))
#define N 50010
#define S 2000010
using namespace std; void gn( int &a ) {
char ch;
ch = getchar();
while( ch<''||ch>'' ) ch=getchar();
a = ;
while( ''<=ch&&ch<='' ) {
a = a*+ch-'';
ch = getchar();
}
} int n, m;
int head[N], dest[N+N], wght[N+N], next[N+N], ntot;
int vis[N], dis[N], siz[N], bac[N], fat[N], tot_siz, cur_root;
int qdis[S], qlf[S], qrg[S], clf, crg, ind;
int stm[S][], bin[], log[N];
int qu[N], bg, ed; struct Paths {
int lf, rg, mx, cur;
Paths( int lf, int rg, int mx, int cur ):lf(lf),rg(rg),mx(mx),cur(cur) {}
bool operator<( const Paths & b ) const {
return qdis[mx]+qdis[cur] < qdis[b.mx]+qdis[b.cur];
}
};
priority_queue<Paths> pq; void insert( int u, int v, int w ) {
ntot++;
next[ntot] = head[u];
wght[ntot] = w;
dest[ntot] = v;
head[u] = ntot;
}
void dfs_dis( int u ) {
ind++;
qdis[ind] = dis[u];
qlf[ind] = clf;
qrg[ind] = crg;
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t], w=wght[t];
if( vis[v] || v==fat[u] ) continue;
dis[v] = dis[u]+w;
fat[v] = u;
dfs_dis( v );
}
} void dfs_root( int u ) {
siz[u] = ;
bac[u] = ;
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( vis[v] || v==fat[u] ) continue;
fat[v] = u;
dfs_root( v );
siz[u] += siz[v];
if( siz[v]>bac[u] ) bac[u]=siz[v];
}
if( bac[u]<tot_siz-siz[u] ) bac[u] = tot_siz-siz[u];
if( bac[cur_root]>bac[u] ) cur_root=u;
}
void build_vdcp( int rt ) {
tot_siz = siz[rt];
cur_root = ;
fat[rt] = rt;
dfs_root( rt );
rt = cur_root;
/* find the core of the block that not cross the vertex of visited */
/*
qu[bg=ed=1] = rt;
fat[rt] = rt;
siz[rt] = bac[rt] = 0;
while( ed>=bg ) {
int u=qu[bg++];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t];
if( vis[v] || v==fat[u] ) continue;
qu[++ed] = v;
fat[v] = u;
siz[u] = bac[u] = 0;
}
}
for( int i=ed; i>=1; i-- ) {
int u=qu[i];
int p=fat[u];
siz[u]++;
siz[p] += siz[u];
if( bac[p]<siz[u] ) bac[p]=siz[u];
}
for( int i=ed; i>=1; i-- ) {
int u=qu[i];
if( bac[u]<siz[rt]-siz[u] ) bac[u]=siz[rt]-siz[u];
}
for( int i=ed; i>=1; i-- ) {
int u=qu[i];
if( bac[rt]>bac[u] ) rt=u;
}
*/
/* get the info of cur core */
ind++;
qdis[ind] = ;
qlf[ind] = qrg[ind] = ;
clf = crg = ind;
vis[rt] = true;
for( int t=head[rt]; t; t=next[t] ) {
int u=dest[t], w=wght[t];
if( vis[u] ) continue;
fat[u] = rt;
dis[u] = w;
fat[u] = u;
dfs_dis( u );
crg = ind;
}
for( int t=head[rt]; t; t=next[t] ) {
int u=dest[t];
if( vis[u] ) continue;
build_vdcp( u );
}
}
void build_stable() {
bin[] = ;
for( int i=; i<; i++ ) bin[i]=bin[i-]<<;
log[] = -;
for( int i=; i<=n; i++ ) log[i]=log[i>>]+;
for( int i=; i<=ind; i++ ) stm[i][] = i;
for( int p=; p<=log[n]; p++ )
for( int i=; i<=ind-bin[p]+; i++ ) {
int a = stm[i][p-];
int b = stm[i+bin[p-]][p-];
stm[i][p] = qdis[a]>qdis[b] ? a : b;
}
}
int rmq( int lf, int rg ) {
int len = rg-lf+;
int p = log[len];
int a = stm[lf][p];
int b = stm[rg-bin[p]+][p];
return qdis[a]>qdis[b] ? a : b;
}
int main() {
gn(n), gn(m);
for( int i=,u,v,w; i<n; i++ ) {
gn(u), gn(v), gn(w);
insert( u, v, w );
insert( v, u, w );
}
bac[] = n, siz[] = n;
build_vdcp( );
build_stable();
for( int i=; i<=ind; i++ )
if( qlf[i] ) pq.push( Paths(qlf[i],qrg[i],rmq(qlf[i],qrg[i]),i) );
for( int i=; i<=m; i++ ) {
Paths pth = pq.top();
pq.pop();
printf( "%d\n", qdis[pth.mx]+qdis[pth.cur] );
if( pth.lf<=pth.mx- ) pq.push( Paths(pth.lf,pth.mx-,rmq(pth.lf,pth.mx-),pth.cur) );
if( pth.rg>=pth.mx+ ) pq.push( Paths(pth.mx+,pth.rg,rmq(pth.mx+,pth.rg),pth.cur) );
}
}

bzoj 3784的更多相关文章

  1. BZOJ 3784: 树上的路径

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

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

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

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

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

  4. 树上的路径 BZOJ 3784

    树上的路径 [问题描述] 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距 ...

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

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

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

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

  7. 洛谷 3784(bzoj 4913) [SDOI2017]遗忘的集合——多项式求ln+MTT

    题目:https://www.luogu.org/problemnew/show/P3784 https://www.lydsy.com/JudgeOnline/problem.php?id=4913 ...

  8. BZOJ 2127: happiness [最小割]

    2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1815  Solved: 878[Submit][Status][Di ...

  9. BZOJ 3275: Number

    3275: Number Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 874  Solved: 371[Submit][Status][Discus ...

随机推荐

  1. 22、WebDriver

    什么是WebDriver?1.Webdriver(Selenium2)是一种用于Web应用程序的自动测试工具:2.它提供了一套友好的API:3.Webdriver完全就是一套类库,不依赖任何测试框架, ...

  2. Git HTTPS 方式自动保存用户名密码

    一行命令搞定: git config --global credential.helper wincred 第一次输入用户名和密码提交,第二次就不需要了 参考: https://help.github ...

  3. 老版本ubuntu更新源地址以及sources.list的配置方法 转

    转自(http://blog.csdn.net/snaking616/article/details/52966634) 1.国内可用的更新源地址: (1)中科大地址 http://mirrors.u ...

  4. Battery Charging Specification 1.2 中文详解 来源:www.chengxuyuans.com

    1. Introduction 1.1 Scope 规范定义了设备通过USB端口充电的检测.控制和报告机制,这些机制是USB2.0规范的扩展,用于专用 充电器(DCP).主机(SDP).hub(SDP ...

  5. 64_o2

    openrdf-sesame-queryrender-2.8.10-2.fc26.noarch..> 11-Feb-2017 18:38 52014 openrdf-sesame-queryre ...

  6. [写出来才有价值系列:node.js]node.js 02-,learnyounode

    安装learnyounode: npm install g learnyounode 官方说直接 但是我发现不行,很慢几乎就是死在那里了 还好有淘宝的东西给我们用https://npm.taobao. ...

  7. [ python ] 匿名函数和高阶函数

    匿名函数 描述:    关键字 lambda 定义的函数    语法: 函数名 = lambda 参数:返回值 返回值:    函数返回结果值 实例: 一个参数的匿名函数: func = lambda ...

  8. Crypt加密函数简介(C语言)

    定义函数 char * crypt (const char *key,const char * salt); 函数说明 crypt是个密码加密函数,它是基于Data Encryption Standa ...

  9. logstash参数配置

    input配置: file:读取文件 input { file{ path => ["/var/log/*.log","/var/log/message" ...

  10. 使用 Python 的 sounddevice 包录制系统声音

    博客中的文章均为meelo原创,请务必以链接形式注明本文地址 sounddevice是一个与Numpy兼容的录音以及播放声音的包. 安装sounddevice包 直接通过pip就能安装. pip in ...