bzoj 3784
第三道点分治。
首先找到黄学长的题解,他叫我参考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的更多相关文章
- BZOJ 3784: 树上的路径
Description 问一棵树上前 \(k\) 大路径的边权. Sol 边分治. 非常感谢数据没有菊花图. 为了写写边分治试试然后就开了这道题. 边分治非常好想,选一条重边,分成两部分,然后分别求最 ...
- bzoj 3784: 树上的路径 堆维护第k大
3784: 树上的路径 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 88 Solved: 27[Submit][Status][Discuss] ...
- BZOJ.3784.树上的路径(点分治 贪心 堆)
BZOJ \(Description\) 给定一棵\(n\)个点的带权树,求树上\(\frac{n\times(n-1)}{2}\)条路径中,长度最大的\(m\)条路径的长度. \(n\leq5000 ...
- 树上的路径 BZOJ 3784
树上的路径 [问题描述] 给定一个N个结点的树,结点用正整数1..N编号.每条边有一个正整数权值.用d(a,b)表示从结点a到结点b路边上经过边的权值.其中要求a<b.将这n*(n-1)/2个距 ...
- bzoj 3784: 树上的路径【点分治+st表+堆】
参考:https://www.cnblogs.com/CQzhangyu/p/7071477.html 神奇的点分治序(或者叫点剖?).就是把点分治扫过的点依次放进队列里,然后发现,对于每一棵树摊到序 ...
- BZOJ 3784: 树上的路径 点分治+二分+set
很容易想出二分这个思路,但是要想办法去掉一个 $log$. 没错,空间换时间. 双指针的部分错了好几次~ Code: #include <set> #include <queue&g ...
- 洛谷 3784(bzoj 4913) [SDOI2017]遗忘的集合——多项式求ln+MTT
题目:https://www.luogu.org/problemnew/show/P3784 https://www.lydsy.com/JudgeOnline/problem.php?id=4913 ...
- BZOJ 2127: happiness [最小割]
2127: happiness Time Limit: 51 Sec Memory Limit: 259 MBSubmit: 1815 Solved: 878[Submit][Status][Di ...
- BZOJ 3275: Number
3275: Number Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 874 Solved: 371[Submit][Status][Discus ...
随机推荐
- 郑轻校赛 2127 tmk射气球 (数学)
Description 有一天TMK在做一个飞艇环游世界,突然他发现有一个气球匀速沿直线飘过,tmk想起了他飞艇上有一把弓,他打算拿弓去射气球,为了提高射击的准确性,他首先在飞艇上找到一个离气球最近的 ...
- Linux Deploy 使用 Repository部署Linux系统
Linux Deploy 使用 Repository部署Linux系统 为了解决镜像不稳定导致包下载错误,能得到一个稳定环境,可以使用linux deploy导出功能. 这里提供两个制作好的包 用户名 ...
- matlab求逆运算:左除( \ )和右除( / ),inv,pinv
矩阵求逆可以使用左除(\)和右除(/),inv,pinv 首先了解需要求逆的矩阵A是否为奇异方阵 inv 若A为非奇异方阵,则存在逆矩阵,可利用inv求逆: inv(A) pinv 若需要求逆的矩阵A ...
- attachEvent 中this指向
IE中使用的事件绑定函数与Web标准的不同,而且this指向也不一样,Web标签中的this指向与传统事件绑定中的this一样,是当前目标,但是IE中事件绑定函数中this指向,通过使用call或ap ...
- OTA之流式更新及shell实现
在OTA升级时,需要从网络下载OTA包,并写到flash上的对应分区中. 最简单的方式是将下载与更新分离,先将完整的数据包下载到本地,再将本地的OTA包更新到flash上.方便可靠. 但这种方式的问题 ...
- PHP 快速建立一个对象
前言 PHP 中的数组(尤其关联数组)是经常使用的 —— 因为方便.在一些框架中也经常见到返回数组格式的配置参数.然而有些时候可能需要对象而非数组类型的配置参数,在查阅网络资料后找到了方法,作以记录. ...
- SPOJ D-query(莫队算法模板)
题目链接:http://www.spoj.com/problems/DQUERY/ 题目大意:给定一个数组,每次询问一个区间内的不同元素的个数 解题思路:直接套莫队的裸题 #include<cs ...
- (转)Opencv卷积操作
转自:http://www.2cto.com/kf/201312/267308.html Mask Operation filter2D函数 Last Edit 2013/12/24 所谓的Mask ...
- JavaWeb知识回顾-Servlet常用类、接口及其方法
今天主要把servlet的一些常用的类.接口和方法简单回顾一下. javax.servlet包 1.javax.servlet.Servlet接口 接口用于开发servlet,所有的servlet都要 ...
- csv 文件乱码问题
问题背景: Pandas.DataFrame 数据结构df在调用df.to_csv()方法生成csv文件格式的字符串(调用df.to_csv('test.csv')直接生成文件也有这个问题)作为字符串 ...