[BJOI2010]次小生成树
OJ题号:
BZOJ1977、COGS2453
题目大意:
给你一个无向连通图,求严格次小生成树。
思路:
对于一般次小生成树,我们有一个结论:一般次小生成树一定可以通过替换掉最小生成树某一条边得到。
因此对于一般次小生成树,我们只需要枚举不在MST上的每一条边,并枚举这条边对应两点路径上的所有边,尝试交换这两条边即可。
显然枚举树上每一条边的复杂度是O(n)的,会TLE,因此我们可以用树剖或者树上倍增的方法记录区间最大边。
然而这题要求的是严格次小生成树,所以万一你枚举的这两条边相等就WA了。
为了保险起见,我们再记录区间最大边的同时,还要记录区间严格次大边。
然后枚举的时候只要判断当前区间最大边是否和那条非树边相等,如果相等的话就取那条次大边即可。
一开始因为没有权限号就去COGS上交,然后随随便便就A了,还跑了Rank1。
但是据说那里数据比较水,就找q234rty借了权限号,去BZOJ上交,果然WA了。
随机了一个小数据,发现是最后倍增求最大树边的时候最后一层没跳上去。
去网上拉了一个程序对拍,发现无限WA。
拿了一个数据手动模拟了一遍,发现原来是网上的题解错了。。
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const long long inf=0x7fffffffffffffffll;
const int V=,logV=;
inline int log2(const float x) {
return ((unsigned&)x>>&)-;
}
class DisjointSet {
private:
int anc[V];
int Find(const int &x) {
return x==anc[x]?x:anc[x]=Find(anc[x]);
}
public:
DisjointSet() {
for(register int i=;i<V;i++) {
anc[i]=i;
}
}
void Union(const int &x,const int &y) {
anc[Find(x)]=Find(y);
}
bool isConnected(const int &x,const int &y) {
return Find(x)==Find(y);
}
};
DisjointSet s;
struct Edge1 {
int u,v,w;
bool inMST;
bool operator < (const Edge1 &another) const {
return w<another.w;
}
};
std::vector<Edge1> e1;
struct Edge {
int to,w;
};
std::vector<Edge> e[V];
inline void add_edge(const int &u,const int &v,const int &w) {
e[u].push_back((Edge){v,w});
}
long long mst=;
inline void kruskal() {
std::sort(e1.begin(),e1.end());
for(register unsigned i=;i<e1.size();i++) {
const int &u=e1[i].u,&v=e1[i].v,&w=e1[i].w;
if(s.isConnected(u,v)) continue;
s.Union(u,v);
add_edge(u,v,w);
add_edge(v,u,w);
e1[i].inMST=true;
mst+=w;
}
}
int anc[V][logV],max[V][logV],max2[V][logV];
int dep[V];
std::queue<int> q;
inline void bfs() {
q.push();
while(!q.empty()) {
const int x=q.front();
q.pop();
dep[x]=dep[anc[x][]]+;
for(register int i=;i<=log2(dep[x]);i++) {
anc[x][i]=anc[anc[x][i-]][i-];
max[x][i]=std::max(max[x][i-],max[anc[x][i-]][i-]);
if(max[x][i-]!=max[anc[x][i-]][i-]) {
max2[x][i]=std::min(max[x][i-],max[anc[x][i-]][i-]);
} else {
max2[x][i]=std::max(max2[x][i-],max2[anc[x][i-]][i-]);
}
}
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i].to;
if(y==anc[x][]) continue;
anc[y][]=x;
max[y][]=e[x][i].w;
q.push(y);
}
}
}
inline int maxEdge(int x,int y,const int &w) {
int tmax=;
while(dep[x]!=dep[y]) {
if(dep[x]<dep[y]) std::swap(x,y);
for(register int i=log2(dep[x]);i>=;i--) {
if(dep[anc[x][i]]>=dep[y]) {
if(max[x][i]<w) {
tmax=std::max(tmax,max[x][i]);
} else if(max2[x][i]<w) {
tmax=std::max(tmax,max2[x][i]);
}
x=anc[x][i];
}
}
}
if(x==y) return tmax;
for(register int i=log2(dep[x]);i>=;i--) {
if(anc[x][i]!=anc[y][i]) {
if(max[x][i]<w) {
tmax=std::max(tmax,max[x][i]);
} else if(max2[x][i]<w) {
tmax=std::max(tmax,max2[x][i]);
}
if(max[y][i]<w) {
tmax=std::max(tmax,max[y][i]);
} else if(max2[y][i]<w) {
tmax=std::max(tmax,max2[y][i]);
}
x=anc[x][i],y=anc[y][i];
}
}
if(max[x][]<w) {
tmax=std::max(tmax,max[x][]);
} else if(max2[x][]<w) {
tmax=std::max(tmax,max2[x][]);
}
if(max[y][]<w) {
tmax=std::max(tmax,max[y][]);
} else if(max2[y][]<w) {
tmax=std::max(tmax,max2[y][]);
}
return tmax;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("secmst.in","r+",stdin);
freopen("secmst.out","w+",stdout);
#endif
int n=getint(),m=getint();
for(register int i=;i<=m;i++) {
const int u=getint(),v=getint(),w=getint();
e1.push_back((Edge1){u,v,w,false});
}
kruskal();
bfs();
long long ans=inf;
for(register unsigned i=;i<e1.size();i++) {
if(e1[i].inMST) continue;
const int &u=e1[i].u,&v=e1[i].v,&w=e1[i].w;
ans=std::min(ans,mst-maxEdge(u,v,w)+w);
}
printf("%lld\n",ans);
#ifndef ONLINE_JUDGE
fclose(stdin),fclose(stdout);
#endif
return ;
}
[BJOI2010]次小生成树的更多相关文章
- [BJOI2010] 严格次小生成树
题目链接 一个严格次小生成树的模板题. 看到次小生成树,我们有一个很直观的想法就是先构造出来最小生成树,然后将这个最小生成树上面最大的一条边替换成和它值最相近而且比他大的边. 那么首先就是用krusk ...
- HDU 4081Qin Shi Huang's National Road System(次小生成树)
题目大意: 有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点.秦始皇希望这所有n-1条路长度之和最短.然后徐福突然有冒出来,说是他有魔法,可以不用人力.财力就变 ...
- POJ1679 The Unique MST[次小生成树]
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28673 Accepted: 10239 ...
- The Unique MST(次小生成树)
Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22335 Accepted: 7922 Description Give ...
- URAL 1416 Confidential --最小生成树与次小生成树
题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1 解法:用Kruskal求最小生成树,标记用过的边.求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就 ...
- POJ1679The Unique MST(次小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 25203 Accepted: 8995 D ...
- [kuangbin带你飞]专题八 生成树 - 次小生成树部分
百度了好多自学到了次小生成树 理解后其实也很简单 求最小生成树的办法目前遇到了两种 1 prim 记录下两点之间连线中的最长段 F[i][k] 之后枚举两点 若两点之间存在没有在最小生成树中的边 那么 ...
- URAL 1416 Confidential(次小生成树)
题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1416 Zaphod Beeblebrox — President of the Impe ...
- ACM题目————次小生成树
Description 最小生成树大家都已经很了解,次小生成树就是图中构成的树的权值和第二小的树,此值也可能等于最小生成树的权值和,你的任务就是设计一个算法计算图的最小生成树. Input 存在多组数 ...
随机推荐
- 手动刷入Android 4.4.1 KOT49E OTA更新包
一.Android 4.4 KitKat Google前段时间发布了Android新版本Android 4.4 KitKat,由于我的Nexus 4也是托朋友从US带回来的,所以很快就收到了Googl ...
- Servlet笔记5--设置欢迎页面及HTTP状态码404、500
欢迎页面: 代码详解: web.xml配置文件: <?xml version="1.0" encoding="UTF-8"?> <web-ap ...
- HTTP::Request 用 add-content 添加 POST参数
sub MAIN($cmd) { use HTTP::UserAgent; my $r = HTTP::Request.new(); $r.uri: 'http://localhost/a.php'; ...
- JUnit基本介绍
一.什么是单元测试 单元测试(Unit Testing)是指在计算机编程中,针对程序模块来进行正确性检验的测试工作.单元测试的特点如下: ※ 程序单元是应用最小的可测试部件,通常采用基于类或者类的方 ...
- php环境搭建 (window环境下 eclipse+Wampserver)
看了好多的环境搭建感觉好复杂呀,自己搞了一下简单的可以用了 php的手册 http://www.php.net/manual/zh/ 一,下载 1,下载eclipse http://www.ecl ...
- No.1 selenium学习之路之浏览器操作
selenium基础,首先就是浏览器的相关操作 下面描述几种浏览器的常用操作 1.打开浏览器 webdriver后面添加想要打开的浏览器 Ie或者Chrome 2.打开指定页面(百度) 3.休眠时间 ...
- ROS数据可视化工具Rviz和三维物理引擎机器人仿真工具V-rep Morse Gazebo Webots USARSimRos等概述
ROS数据可视化工具Rviz和三维物理引擎机器人仿真工具V-rep Morse Gazebo Webots USARSimRos等概述 Rviz Rviz是ROS数据可视化工具,可以将类似字符串文本等 ...
- Nginx 虚拟主机 VirtualHost 配置
Nginx 是一个轻量级高性能的 Web 服务器, 并发处理能力强, 对资源消耗小, 无论是静态服务器还是小网站, Nginx 表现更加出色, 作为 Apache 的补充和替代使用率越来越高. 我在& ...
- 什么是 CLR(转)
CLR(公用语言运行时)和Java虚拟机一样也是一个运行时环境,它负责资源管理(内存分配和垃圾收集),并保证应用和底层操作系统之间必要的分离..NET提供了一个运行时环境,叫做公用语言运行时(Comm ...
- hdu 5122 (2014北京现场赛 K题)
把一个序列按从小到大排序 要执行多少次操作 只需要从右往左统计,并且不断更新最小值,若当前数为最小值,则将最小值更新为当前数,否则sum+1 Sample Input255 4 3 2 155 1 2 ...