(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 ...
随机推荐
- 【Tools】ubuntu16.04安装搜狗输入法
Ubuntu16,04 安装搜狗输入法 1.下载搜狗输入法的安装包 下载地址为:http://pinyin.sogou.com/linux/ 2.按键Ctr+Alt+T打开终端,输入以下命令切换到下载 ...
- Golang学习 - strconv 包--数据类型转换
// 将布尔值转换为字符串 true 或 false func FormatBool(b bool) string // 将字符串转换为布尔值 // 它接受真值:1, t, T, TRUE, true ...
- ss-redir 的 iptables 配置(透明代理)
透明代理指对客户端透明,客户端不需要进行任何设置就使用了网管设置的代理规则 创建 /etc/ss-redir.json 本地监听 7777 运行ss-redir -v -c /etc/ss-redir ...
- bzoj 1171 大sz的游戏& 2892 强袭作战 (线段树+单调队列+永久性flag)
大sz的游戏 Time Limit: 50 Sec Memory Limit: 357 MBSubmit: 536 Solved: 143[Submit][Status][Discuss] Des ...
- js中checkbox的全选和反选的实现
<head> <meta charset="utf-8"/> <script type="text/javascript"> ...
- hibernate的事务管理和session对象的详解
//开启事务 transaction=session.beginTransaction(); 上面为开启事务 transaction.commit();这个为提交事务 从session对象中获取事务后 ...
- Docker镜像的构成__Dockerfile
相比docker commit来说,Dockerfile的方法会更加自动化,更加方便快捷,而且功能也更强大.拿构建Nginx容器举例. 先创建一个目录 mkdir /opt/docker-file 进 ...
- Ecshop中transport和jquery不兼容的解决方案
1.修改文件:/js/transport.js,在最底部增加代码 if (Object.prototype.toJSONString){ var oldToJSONString = Object.to ...
- FZU - 2150 bfs [kuangbin带你飞]专题一
题意:两个人玩很变态的游戏,将一个草坪的某两个点点燃,点燃的草坪可以向上下左右四个方向扩散,问能否将整块草坪上面的草都点燃.如果能,输出最短时间(^_^他们就能玩更变态的游戏了),如果不能,输出-1. ...
- LOJ6001 - 「网络流 24 题」太空飞行计划
原题链接 Description 有个实验和个仪器,做实验有报酬买仪器有花费.每个实验都需要一些仪器,求最大净收益(实验报酬仪器花费),并输出一组方案. Solution 实验向所需仪器连边,实验的点 ...