第三道点分治。

首先找到黄学长的题解,他叫我参考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. javascript 中的 this 关键字详解

    1.javascript 中 什么是 this? this 指的是当前行为执行的主体,或者是当前方法执行的主体 context:是当前行为或者方法执行的环境 实例: xx 去北京饭店吃东西:上下文是“ ...

  2. JavaScript三种绑定事件的方式

    JavaScript三种绑定事件的方式: 1. <div id="btn" onclick="clickone()"></div> // ...

  3. bzoj 2741 可持久化trie

    首先我们设si为前i个数的xor和,那么对于询问区间[i,j]的xor和,就相当于si-1^sj,那么对于这道题的询问我们可以处理处si,然后对于询问[l,r],可以表示为在区间[l-1,r]里找两个 ...

  4. python之supervisor进程管理工具

    supervisor是python写的一个管理进程运行的工具,可以很方便的监听.启动.停止.重启一个或多个进程:有了supervisor后,就不用字节写启动和监听的shell脚本了,非常方便. sup ...

  5. Python学习笔记——数据结构和算法(一)

    1.解压序列赋值给多个变量 任何的序列(或者是可迭代对象)可以通过一个简单的赋值语句解压并赋值给多个变量. 唯一的前提就是变量的数量必须跟序列元素的数量是一样的. >>> data ...

  6. html基础-css-选择器

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  7. java基础4 函数

    本文知识点(目录): 1.函数的概述    2.函数的格式    3.自定义函数    4.函数的特点    5.函数的应用    6.函数的重载 1.函数的概述 发现不断进行加法运算,为了提高代码的 ...

  8. Python抓取微博评论

    本人是张杰的小迷妹,所以用杰哥的微博为例,之前一直看的是网页版,然后在知乎上看了一个抓取沈梦辰的微博评论的帖子,然后得到了这样的网址 然后就用m.weibo.cn进行网站的爬取,里面的微博和每一条微博 ...

  9. scala学习笔记3

    一.条件表达式 在scala中if/else表达式有值,这个值就是跟在if或者else之后的表达式的值. scala> val x = 10 x: Int = 10 scala> val ...

  10. 洛谷P2464 [SDOI2008] 郁闷的小j [分块]

    题目传送门 郁闷的小j 题目描述 小J是国家图书馆的一位图书管理员,他的工作是管理一个巨大的书架.虽然他很能吃苦耐劳,但是由于这个书架十分巨大,所以他的工作效率总是很低,以致他面临着被解雇的危险,这也 ...