(luogu4180) [Beijing2010组队]次小生成树Tree
严格次小生成树
首先看看如果不严格我们怎么办。
由此,我们发现一个结论,求非严格次小生成树,只需要先用kruskal算法求得最小生成树,然后暴力枚举非树边,替换路径最大边即可。
那要是严格呢?
我们发现如果是严格的次小生成树,那么将一条边替换另一条时,这两条边的权值一定不相同
但是,我们知道,替换边肯定大于等于被替换边(因为如果替换边小于被替换边,就存在一颗包含替换边而不包含被替换边的一棵权值更小的生成树,原树就不是最小生成树了)
所以替换边要么等于路径上最大的边,要么比最大的边还大。
利用这个性质,我们只需要维护路径中的最大值和次大值,当替换边等于路径上的最大值,我们直接换用严格次大值即可。
一些细节
1.我维护两点之间路径最大值用的是LCT,但是正解是LCA。LCT必须要开O2才能跑过去。
2.数组要开足够大,最后统计答案时要开long long,不然会爆int
我的代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define rg register int
#define ll long long
#define RG register
#define il inline
using namespace std;
il ll gi() {
RG ll x=0;rg o=0;RG char ch=getchar();
while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
if(ch=='-') o=1,ch=getchar();
while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return o?-x:x;
}
int n,m;
#define SZ 7000010
struct Edge {int a,b;ll w;}e[SZ];
bool cmp(Edge a,Edge b) {return a.w<b.w;}
#define lson tr[x].ch[0]
#define rson tr[x].ch[1]
struct Splaytree{int fa,ch[2],rev,mxp,mxp2;}tr[SZ];
il void pushup(rg x)
{
tr[x].mxp=x; tr[x].mxp2=0;
if(e[tr[lson].mxp].w>e[tr[x].mxp].w) tr[x].mxp=tr[lson].mxp;
if(e[tr[rson].mxp].w>e[tr[x].mxp].w) tr[x].mxp=tr[rson].mxp;
// 维护 最大
if(e[tr[lson].mxp].w!=e[tr[x].mxp].w && (e[tr[lson].mxp].w>e[tr[x].mxp].w||!tr[x].mxp2) ) tr[x].mxp2=tr[lson].mxp;
if(e[tr[lson].mxp2].w!=e[tr[x].mxp].w && (e[tr[lson].mxp2].w>e[tr[x].mxp].w||!tr[x].mxp2) ) tr[x].mxp2=tr[lson].mxp2;
if(e[tr[rson].mxp].w!=e[tr[x].mxp].w && (e[tr[rson].mxp].w>e[tr[x].mxp].w||!tr[x].mxp2) ) tr[x].mxp2=tr[rson].mxp;
if(e[tr[rson].mxp2].w!=e[tr[x].mxp].w && (e[tr[rson].mxp2].w>e[tr[x].mxp].w||!tr[x].mxp2) ) tr[x].mxp2=tr[rson].mxp2;
// 维护严格次大
}
il void pushdown(rg x)
{
if(tr[x].rev)
{
tr[lson].rev^=1,tr[rson].rev^=1;
swap(lson,rson),tr[x].rev=0;
}
}
il bool isroot(rg x)
{
return tr[tr[x].fa].ch[0]!=x && tr[tr[x].fa].ch[1]!=x;
}
il void rotate(rg x)
{
rg y=tr[x].fa,z=tr[y].fa;
rg k=tr[y].ch[1]==x;
if(!isroot(y)) tr[z].ch[y==tr[z].ch[1]]=x;tr[x].fa=z;
tr[y].ch[k]=tr[x].ch[k^1],tr[tr[x].ch[k^1]].fa=y;
tr[x].ch[k^1]=y,tr[y].fa=x;
pushup(y),pushup(x);
}
int stk[SZ],top;
il void splay(rg x)
{
stk[top=1]=x;
for(rg i=x;!isroot(i);i=tr[i].fa) stk[++top]=tr[i].fa;
for(;top;--top) pushdown(stk[top]);
while(!isroot(x))
{
rg y=tr[x].fa,z=tr[y].fa;
if(!isroot(y))
(tr[y].ch[0]==x)^(tr[z].ch[0]==y)?rotate(x):rotate(y);
rotate(x);
}
}
il void access(rg x) {for(rg y=0;x;y=x,x=tr[x].fa)splay(x),rson=y,pushup(x);}
il void makeroot(rg x) {access(x);splay(x);tr[x].rev^=1;}
il int findroot(rg x) {access(x);splay(x);while(lson) x=lson;return x;}
il void split(rg x,rg y) {makeroot(x);access(y);splay(y);}
il int query(rg x,rg y) {split(x,y);return tr[y].mxp;} //求x 到 y最大值
il int query2(rg x,rg y) {split(x,y);return tr[y].mxp2;} // 求x 到 y严格次大值
il void link(rg x,rg y) {makeroot(x);tr[x].fa=y;}
il void cut(rg x,rg y) {split(x,y);if(tr[y].ch[0]==x)tr[y].ch[0]=tr[x].fa=0;}
int fa[SZ];int find_fa(rg x) {if(x!=fa[x]) fa[x]=find_fa(fa[x]);return fa[x];} //一行并查集
bool check[SZ];
int main()
{
n=gi(),m=gi();
for(rg i=1;i<=m;++i) e[i]=(Edge){gi(),gi(),gi()};
// 先求一遍最小生成树 ans 记录最小生成树边的大小
RG ll ans=0;
sort(e+1,e+1+m,cmp);
for(rg i=1;i<=n;++i) fa[i]=i; // 初始化并查集
for(rg f1,f2,i=1;i<=m;++i)
{
f1=find_fa(e[i].a);
f2=find_fa(e[i].b);
if(f1!=f2)
{
check[i]=1; // check=1 表示最小生成树中有这一条边 反之
fa[f1]=f2;
ans+=e[i].w;
link(e[i].a+m,i);
link(e[i].b+m,i);
}
}
#define INF 2147483647
#define Getmin(a,b) (a)=(a)>(b)?(b):(a)
RG ll Ans=INF;
for(rg f1,f2,i=1;i<=m;++i)
{
if(check[i]) continue; //我们选择不再最小生成树上的边
rg mxp=query(e[i].a+m,e[i].b+m);
if(e[mxp].w==e[i].w)
{
rg mxp2=query2(e[i].a+m,e[i].b+m);
if(!mxp2 || e[mxp2].w==e[mxp].w) continue;
Getmin(Ans,e[i].w-e[mxp2].w);
}
else Getmin(Ans,e[i].w-e[mxp].w);
}
cout<<ans+Ans;
return 0;
}
(luogu4180) [Beijing2010组队]次小生成树Tree的更多相关文章
- BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...
- 1977: [BeiJing2010组队]次小生成树 Tree
1977: [BeiJing2010组队]次小生成树 Tree https://lydsy.com/JudgeOnline/problem.php?id=1977 题意: 求严格次小生成树,即边权和不 ...
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
[BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...
- [BeiJing2010组队]次小生成树 Tree
1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 5168 Solved: 1668[S ...
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树
描述: 就是求一个次小生成树的边权和 传送门 题解 我们先构造一个最小生成树, 把树上的边记录下来. 然后再枚举每条非树边(u, v, val),在树上找出u 到v 路径上的最小边$g_0$ 和 严格 ...
- 【刷题】BZOJ 1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...
随机推荐
- .NET Core使用swagger进行API接口文档管理
一.问题背景 随着技术的发展,现在的开发模式已经更多的转向了前后端分离的模式,在前后端开发的过程中,联系的方式也变成了API接口,但是目前项目中对于API的管理很多时候还是通过手工编写文档,每次的需求 ...
- wordpress配置固定链接nginx访问404问题解决方法
WordPress支持使用固定链接,但是在ngnix环境下,访问页面后出现404, 其实官方是有文档说明的,需要单独写配置, 我这边配置的示例代码如下: server { listen 8 ...
- 配置可以通过http协议访问的svn服务器
通过HTTP协议访问版本库是Subversion的亮点之一,这种方式具备许多svnserve服务器所没有的特性,使用上更加灵活. 关于mode_day_svn模块: 由于Subversion需要版本化 ...
- maven配置全局的jdk和配置局部的jdk
配置全局的jdk需要修改maven的setting.xml文件 <profile> <id>jdk17</id> <activation> <ac ...
- Python基础——条件判断
Python版本:3.6.2 操作系统:Windows 作者:SmallWZQ 到目前为止,Python基础系列的文章中的程序都是一条一条语句顺序执行的.在本章中,我会重点介绍让程序选择是否执行语 ...
- 安装git,gitlab和TortoiseGit
全部都是默认配置安装 需注册用户:用户名尽量好认 测试用户: 注册成功: 生成密钥: 1.首先使用TortoiseGit自带的Puttygen创建本地的公/私钥对 2.点击Generate按钮,在窗口 ...
- 一个逼格很低的appium自动化测试框架
Github地址: https://github.com/wuranxu 使用说明 1. 安装配置Mongo数据库 下载地址 mongo是用来存放元素定位的,截图如下: 通过case_id区分每个ca ...
- 故障定位之查找附近点GeoHash研讨
随着移动终端的普及,很多应用都基于LBS功能,附近的某某(餐馆.银行.妹纸等等). 基础数据中,一般保存了目标位置的经纬度:利用用户提供的经纬度,进行对比,从而获得是否在附近. 目标:查找附近的XXX ...
- (转载)windows下mysql忘记密码
Mysql版本:5.1 1. 首先检查mysql服务是否启动,若已启动则先将其停止服务,可在开始菜单的运行,使用命令: net stop mysql 打开第一个cmd窗口,切换到mysql的bin目录 ...
- word自动备份,word误删内容恢复
有个问题时长困扰着我,就是一次不小心把word里面的一部分内容误删了之后,又手残点击ctrl+s给保存了,要是立即ctrl+z还能撤销,可要是关闭了word才想起来撤销就来不及啦,现在终于找到解决的办 ...