【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并
题目描述
求一张图的严格次小生成树的边权和,保证存在。
输入
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。
输出
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
样例输入
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
样例输出
11
题解
最小生成树+权值线段树合并
首先有一个常用的结论:次小生成树(无论是否严格)只要存在,则一定可以由最小生成树仅改变一条边构成,并且添加的边一定能覆盖删除的边。
然后考虑删除哪条边或者加入哪条边均可。
然后只会写数据结构的傻逼GXZ的做法比较naive:考虑每一条非树边的贡献,给两个端点打加入标记,给LCA打删除标记,自底向上跑权值线段树合并,维护出现过的最小权值和次小权值,然后搜到每条边时用最小的不相等的权值更新答案。
正解貌似是考虑加入哪条非树边,倍增找最小次小值?不管了反正512MB内存能过。。。
时间复杂度$O(n\log n)$
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
#define M 1000000000
#define inf 0x7f7f7f7f
using namespace std;
struct data
{
int x , y , z;
bool operator<(const data &a)const {return z < a.z;}
}a[N * 3];
int f[N] , flag[N * 3] , head[N] , to[N << 1] , len[N << 1] , next[N << 1] , cnt , fa[N][20] , deep[N] , val[N] , log[N];
int ls[N << 7] , rs[N << 7] , si[N << 7] , mx[N << 7] , sx[N << 7] , tot , root[N] , ans = inf;
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
inline void add(int x , int y , int z)
{
to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x)
{
int i;
for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x][0])
fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , val[to[i]] = len[i] , dfs(to[i]);
}
inline int lca(int x , int y)
{
int i;
if(deep[x] < deep[y]) swap(x , y);
for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
if(deep[x] - deep[y] >= (1 << i))
x = fa[x][i];
if(x == y) return x;
for(i = log[deep[x]] ; ~i ; i -- )
if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i])
x = fa[x][i] , y = fa[y][i];
return fa[x][0];
}
void pushup(int x)
{
if(mx[ls[x]] == inf) mx[x] = mx[rs[x]] , sx[x] = sx[rs[x]];
else if(sx[ls[x]] == inf) mx[x] = mx[ls[x]] , sx[x] = mx[rs[x]];
else mx[x] = mx[ls[x]] , sx[x] = sx[ls[x]];
}
void update(int p , int a , int l , int r , int &x)
{
if(!x) x = ++tot;
if(l == r)
{
si[x] += a;
if(si[x] > 0) mx[x] = l;
else mx[x] = inf;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) update(p , a , l , mid , ls[x]);
else update(p , a , mid + 1 , r , rs[x]);
pushup(x);
}
int merge(int l , int r , int x , int y)
{
if(!x) return y;
if(!y) return x;
if(l == r)
{
si[x] += si[y];
if(si[x] > 0) mx[x] = l;
else mx[x] = inf;
return x;
}
int mid = (l + r) >> 1;
ls[x] = merge(l , mid , ls[x] , ls[y]);
rs[x] = merge(mid + 1 , r , rs[x] , rs[y]);
pushup(x);
return x;
}
void solve(int x)
{
int i;
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x][0])
solve(to[i]) , root[x] = merge(1 , M , root[x] , root[to[i]]);
if(mx[root[x]] != inf)
{
if(mx[root[x]] != val[x]) ans = min(ans , mx[root[x]] - val[x]);
else if(sx[root[x]] != inf) ans = min(ans , sx[root[x]] - val[x]);
}
}
int main()
{
int n , m , i;
long long sum = 0;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &a[i].x , &a[i].y , &a[i].z);
sort(a + 1 , a + m + 1);
log[0] = -1;
for(i = 1 ; i <= n ; i ++ ) f[i] = i , log[i] = log[i >> 1] + 1;
for(i = 1 ; i <= m ; i ++ )
if(find(a[i].x) != find(a[i].y))
f[f[a[i].x]] = f[a[i].y] , add(a[i].x , a[i].y , a[i].z) , add(a[i].y , a[i].x , a[i].z) , sum += a[i].z , flag[i] = 1;
dfs(1);
memset(mx , 0x7f , sizeof(mx)) , memset(sx , 0x7f , sizeof(sx));
for(i = 1 ; i <= m ; i ++ )
if(!flag[i])
update(a[i].z , 1 , 1 , M , root[a[i].x]) , update(a[i].z , 1 , 1 , M , root[a[i].y]) , update(a[i].z , -2 , 1 , M , root[lca(a[i].x , a[i].y)]);
solve(1);
printf("%lld\n" , sum + ans);
return 0;
}
【bzoj1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+权值线段树合并的更多相关文章
- 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增
[BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...
- 【bzoj2212】[Poi2011]Tree Rotations 权值线段树合并
原文地址:http://www.cnblogs.com/GXZlegend/p/6826614.html 题目描述 Byteasar the gardener is growing a rare tr ...
- 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca
Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...
- bzoj1977 [BeiJing2010组队]次小生成树 Tree
和倍增法求lca差不多,维护每个点往上跳2^i步能到达的点,以及之间的边的最大值和次大值,先求出最小生成树,对于每个非树边枚举其端点在树上的路径的最大值,如果最大值和非树边权值一样则找次大值,然后维护 ...
- bzoj1977 [BeiJing2010组队]次小生成树 Tree——严格次小生成树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977 因为严格,所以要记录到 LCA 的一个次小值: 很快写好,然后改掉一堆错误后终于过了样 ...
- 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 题意: 求严格次小生成树,即边权和不 ...
- [BeiJing2010组队]次小生成树 Tree
1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 5168 Solved: 1668[S ...
随机推荐
- 汉化manjaro下的火狐浏览器
1.下载 汉化包 sudo pacman -S firefox-i18n-zh-cn 2.查看add-ons下的language选项有没有已安装的包 3.在浏览器的地址栏输入 搜索intl.local ...
- (九)Pycharm异常、模块
异常: 当Python检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的"异常" 捕获异常: 格式:try+执行代码······ ...
- css表格
今天写某个平台的前端数据展示 主要使用表格展示 正好复习总结一下css的表格 首先说说thead.tbody.tfoot <thead></thead> <tbody&g ...
- 右键添加git-bash
主要: 右键如果没有git-bash,如何给右键手动添加 前面对右键存在git-bash但使用出现问题的解决,也想到如果右键都没有,该如何给右键添加了,于是接着记录下如何添加的过程: 情形: 手动给右 ...
- Python3乘法口诀表(由上至下+由下至上)
一.所用知识点: 1.变量的使用. 2.循环语句的使用,这里用到的是双while循环.当然,使用其他的循环去做也是可以的.我认为,对于刚刚接触编程的人来说,使用双while循环比较容易理解. 3.使用 ...
- R语言学习笔记(十一):零碎知识点(26-30)
26--aggregate( ) 函数aggregate()对分组中的每一个变量调用tapply()函数. aggregate(a,list,f) 第二个参数必须是列表.也就是因子部分. 第三个参数即 ...
- 教你Zbrush 4R7怎样创建Z球
随着CG行业的迅猛发展,就业门槛大幅度提高,对于从业人员要求就是要“又快又好”,作为一个模型师,常会碰到一天或两天完成一个全身角色的考题,而且还需要角度摆出造型,以前做这个的话,可能比较难,现在有了Z ...
- PHP.42-TP框架商城应用实例-后台17-商品属性3-商品分类的修改与删除
商品分类的修改 1.改表单Goods/edit.html,加下拉框 2.因为商品属性修改涉及商品属性表goods_attr{id,attr_value,attr_id,goods_id}与属性表att ...
- shell -- if参数用法
一.概要1.if与[之间要有空格2.[]与判断条件之间也必须有空格3.]与:之间不能有空格 二.对字符串的判断1.if [ str1=str2 ];then fi ----当两个字符串相同时返回真2 ...
- 20160120使用myeclipse一年开始转IntelliJ IDEA 15做以下总结
20160120使用myeclipse一年开始费元星转IntelliJ IDEA 15做以下总结 1.输入psv就会看到一个psvm的提示,此时点击tab键一个main方法就写好了.psvm 也就是p ...