严格次小生成树

首先看看如果不严格我们怎么办。

非严格次小生成树怎么做

由此,我们发现一个结论,求非严格次小生成树,只需要先用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的更多相关文章

  1. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )

    做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...

  2. 1977: [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree https://lydsy.com/JudgeOnline/problem.php?id=1977 题意: 求严格次小生成树,即边权和不 ...

  3. 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增

    [BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...

  4. [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 5168  Solved: 1668[S ...

  5. 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

    洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...

  6. 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  7. BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树

    描述: 就是求一个次小生成树的边权和 传送门 题解 我们先构造一个最小生成树, 把树上的边记录下来. 然后再枚举每条非树边(u, v, val),在树上找出u 到v 路径上的最小边$g_0$ 和 严格 ...

  8. 【刷题】BZOJ 1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  9. 【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并

    题目描述 求一张图的严格次小生成树的边权和,保证存在. 输入 第一行包含两个整数N 和M,表示无向图的点数与边数. 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z ...

随机推荐

  1. ACE-6.1.0 linux 下的编译与安装步骤

    ACE-6.1.0 linux 下的编译与安装步骤  引用至http://www.cnblogs.com/liangxiaxu/archive/2013/03/07/2948417.html 1.从  ...

  2. mac攻略(2) -- apache站点配置

    [http://www.cnblogs.com/redirect/p/6112164.html] Mac OS X 中默认有两个目录可以直接运行你的 Web 程序, 一个是系统级的 Web 根目录:/ ...

  3. 免费 Https 证书(Let's Encrypt)申请与配置

    之前要申请免费的 https 证书操作步骤相当麻烦,今天看到有人在讨论,就搜索了一下.发现现在申请步骤简单多了. 1. 下载 certbot git clone https://github.com/ ...

  4. 撸一撸Spring Cloud Ribbon的原理-负载均衡器

    在上一篇<撸一撸Spring Cloud Ribbon的原理>中整理发现,RestTemplate内部调用负载均衡拦截器,拦截器内最终是调用了负载均衡器来选择服务实例. 接下来撸一撸负载均 ...

  5. 一个例子理解break和continue的区别

    结论:break用于终止整个循环,而continue用于终止某一次循环.public class Test { public static void main(String[] args) { for ...

  6. HTML5VEDIO标签阿里云-微信浏览器兼容性问题

    在网页展示媒体对象,离不开HTML5的 audio和video对象.但这两个目前来看兼容性方面还得关注一下. 目前在做一个阿里云下载video 并在微信端播放mp4格式的视频的时候,碰到了一些兼容性问 ...

  7. bzoj 2209 [Jsoi2011]括号序列 平衡树

    2209: [Jsoi2011]括号序列 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1404  Solved: 699[Submit][Statu ...

  8. 五子棋的斜对角方向上的规则 -- java编程(简单粗暴版)

    五子棋判断输赢规则 --- 斜对角线方向上 一.左上右下方向上 1.分析图 2.代码 /**判断左上右下方向上是否有连续五颗相同颜色的棋子 * 全部遍历法 */ int loop = 0; boole ...

  9. wpf 如何让控件左右移动

    通过DoubleAnimation可以让控件进行左右移动. <Canvas x:Name="canvas_Shape" HorizontalAlignment="S ...

  10. 算法提高 金属采集 树形DP

    题目链接:金属采集 思路:d(i, j)表示在以i为根结点的子树中使用j个机器人的最小花费.设v为u的一个子节点,从节点i使用k个机器人收集以v为根结点的能量,状态转移方程为d(u, i) = min ...