P4180 【模板】严格次小生成树[BJWC2010]

题目描述

小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值)$\sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)$

这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

输入输出格式

输入格式:

第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

输出格式:

包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

输入输出样例

输入样例#1: 复制

5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
输出样例#1: 复制

11

说明

数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。


Solution

无所不能的链剖Orz!(就是太难调叻!!)

对于一条不在最小生成树上的边,如果要使它在次小生成树上,那就是在这条边的两端点的链的所有边中找一条删掉,要使他最接近次小,那么就是找链中最大的边,这样使增加的边权最小。但是题目要求是严格次小,意味着如果最大边权等于这条非树边边权,那么我们要找次大的边权。

因此线段树上再维护一个严格次大值就好了。

线段树的值是点权下放到边权。所以跳链查询时最后要查询的是$in[v]+1$到$in[u]$,防止把上面的边计算进去。

Code

#include<bits/stdc++.h>
#define LL long long
using namespace std; struct Node {
int u, v, nex, tag; LL w;
Node(int u = , int v = , int nex = , LL w = ) :
u(u), v(v), nex(nex), w(w) { }
} Edge[], a[];
bool cmp(Node a, Node b) { return a.w < b.w; } int h[], stot;
void add(int u, int v, LL w) {
Edge[++stot] = Node(u, v, h[u], w);
h[u] = stot;
} int n, m;
int fa[], siz[], son[], dep[]; LL vson[];
void dfs1(int u, int f) {
fa[u] = f; siz[u] = ; dep[u] = dep[f] + ;
for(int i = h[u]; i; i = Edge[i].nex) {
int v = Edge[i].v;
if(v == f) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v, vson[u] = Edge[i].w;
}
} int top[], in[], idc; LL seq[];
void dfs2(int u, int t, LL w) {
top[u] = t; in[u] = ++idc; seq[idc] = w;
if(son[u]) dfs2(son[u], t, vson[u]);
for(int i = h[u]; i; i = Edge[i].nex) {
int v = Edge[i].v;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v, Edge[i].w);
}
} struct QAQ {
LL ma1, ma2;
} TR[]; void update(int nd) {
TR[nd].ma1 = max(TR[nd << ].ma1, TR[nd << | ].ma1);
TR[nd].ma2 = max(TR[nd].ma1 == TR[nd << ].ma1 ? TR[nd << ].ma2 : TR[nd << ].ma1, TR[nd].ma1 == TR[nd << | ].ma1 ? TR[nd << | ].ma2 : TR[nd << | ].ma1);
} void build(int nd, int l, int r) {
if(l == r) {
TR[nd].ma1 = seq[l];
TR[nd].ma2 = -;
return ;
}
int mid = (l + r) >> ;
build(nd << , l, mid);
build(nd << | , mid + , r);
update(nd);
} QAQ query(int nd, int l, int r, int L, int R) {
if(l >= L && r <= R) return TR[nd];
int mid = (l + r) >> ;
QAQ ans, tmp, res;
ans.ma1 = ans.ma2 = tmp.ma1 = tmp.ma2 = res.ma1 = res.ma2 = ;
if(L <= mid) {
ans = query(nd << , l, mid, L, R);
}
if(R > mid) {
tmp = query(nd << | , mid + , r, L, R);
}
res.ma1 = max(ans.ma1, tmp.ma1);
res.ma2 = max(ans.ma1 == res.ma1 ? ans.ma2 : ans.ma1, tmp.ma1 == res.ma1 ? tmp.ma2 : tmp.ma1);
return res;
} LL query(int u, int v, LL w) {
LL ans = ;
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
QAQ tmp = query(, , n, in[top[u]], in[u]);
ans = max(tmp.ma1 == w ? tmp.ma2 : tmp.ma1, ans);
u = fa[top[u]];
}
if(u == v) return ans;
if(dep[u] < dep[v]) swap(u, v);
QAQ tmp = query(, , n, in[v] + , in[u]);
ans = max(ans, tmp.ma1 == w ? tmp.ma2 : tmp.ma1);
return ans;
} int f[];
int find(int x) {
if(x != f[x]) return f[x] = find(f[x]);
return f[x];
} LL tot;
void Kruskal() {
sort(a + , a + + m, cmp);
for(int i = ; i <= n; i ++) f[i] = i;
for(int i = ; i <= m; i ++) {
int u = a[i].u, v = a[i].v; LL w = a[i].w;
int uu = find(u), vv = find(v);
if(uu != vv) f[uu] = vv, a[i].tag = , tot += w;
}
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= m; i ++) {
int u, v; LL w;
scanf("%d%d%lld", &u, &v, &w);
a[i].u = u, a[i].v = v, a[i].w = w;
}
Kruskal();
for(int i = ; i <= m; i ++)
if(a[i].tag) {
add(a[i].u, a[i].v, a[i].w);
add(a[i].v, a[i].u, a[i].w);
}
dfs1(, ); dfs2(, , ); build(, , n);
LL ans = 0x3f3f3f3f;
for(int i = ; i <= m; i ++) {
if(!a[i].tag) {
int u = a[i].u, v = a[i].v; LL w = a[i].w;
LL tmp = query(u, v, w);
ans = min(ans, w - tmp);
}
}
printf("%lld", tot + ans);
return ;
}

【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】的更多相关文章

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

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

  2. 「BZOJ2733」「洛谷3224」「HNOI2012」永无乡【线段树合并】

    题目链接 [洛谷] 题解 很明显是要用线段树合并的. 对于当前的每一个连通块都建立一个权值线段树. 权值线段树处理操作中的\(k\)大的问题. 如果需要合并,那么就线段树暴力合并,时间复杂度是\(nl ...

  3. BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)

    潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...

  4. 【洛谷P4180】严格次小生成树

    题目大意:给定一个 N 个顶点,M 条边的带权无向图,求该无向图的一个严格次小生成树. 引理:有至少一个严格次小生成树,和最小生成树之间只有一条边的差异. 题解: 通过引理可以想到一个暴力,即:先求出 ...

  5. 洛谷P4180 [Beijing2010组队]次小生成树Tree

    题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...

  6. 【洛谷4770】 [NOI2018]你的名字(SAM,线段树合并)

    传送门 洛谷 Solution 做过的比较玄学的后缀自动机. 果然就像\(Tham\)所讲,后缀自动机这种东西考场考了不可能做的出来的... 考虑如果\(l=1,r=|S|\)的怎么做? 直接建后缀自 ...

  7. 洛谷 P4513 小白逛公园-区间最大子段和-分治+线段树区间合并(单点更新、区间查询)

    P4513 小白逛公园 题目背景 小新经常陪小白去公园玩,也就是所谓的遛狗啦… 题目描述 在小新家附近有一条“公园路”,路的一边从南到北依次排着nn个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩 ...

  8. 洛谷.4180.[模板]次小生成树Tree(Kruskal LCA 倍增)

    题目链接 构建完MST后,枚举非树边(u,v,w),在树上u->v的路径中找一条权值最大的边(权为maxn),替换掉它 这样在 w=maxn 时显然不能满足严格次小.但是这个w可以替换掉树上严格 ...

  9. 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree

    原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...

  10. 洛谷P3994 Highway(树形DP+斜率优化+可持久化线段树/二分)

    有点类似NOI2014购票 首先有方程$f(i)=min\{f(j)+(dep_i-dep_j)*p_i+q_i\}$ 这个显然是可以斜率优化的... $\frac {f(j)-f(k)}{dep_j ...

随机推荐

  1. TableView 的那些坑

    1. 分割线填满cell宽度, 并且设置分割线的颜色 1.1 利用系统的分割线填充 1.1.1 tableView 设置如下属性 // 给tableView设置如下属性值 tableView.layo ...

  2. Python之 context manager

    在context manager中,必须要介绍两个概念: with as... , 和 enter , exit. 下文将先介绍with语句,然后介绍 __enter__和exit, 最后介绍cont ...

  3. 修改类不用重启Tomcat加载整个项目

    可以修改类不用重启Tomcat加载整个项目(手工启动) 配置reloadable=true(自动重载) 使用Debug模式,前提是仅限于局部修改.(修改类不用重启--热加载) Tomcat轻小,而We ...

  4. RabbitMQ--work queues(二)

    封装一个task到一个message,并发送到queue.consumer会去除task并执行这个task. 这里我们简化了操作,发送消息到队列中,consumer取出消息计算里面'.'号有几个就sl ...

  5. 使用qshell备份七牛云存储文件

    qshell是利用七牛文档上公开的API实现的一个方便开发者测试和使用七牛API服务的命令行工具.我们可以利用它来将七牛云上存储的文件备份到本地. 它提供Mac OSX, Linux, Windows ...

  6. ThinkPHP小知识点

    ThinkPHP模版中时间戳转换为时间 {$vo.data|date='Y-m-d',###} thinkphp字符截取函数msubstr() ThinkPHP有一个内置字符截取函数mb_substr ...

  7. IntelliJ IDEA + Tomcat 部署问题

    首先要了解下 tomcat的 几种部署方式(大致分为静态部署和动态部署),可以百度,博客:http://qsfwy.iteye.com/blog/466461 IntelliJ IDEA 下部署项目的 ...

  8. Jenkins的授权和访问控制

    默认的Jenkins不包含任何的安全检查,任何人可以修改Jenkins设置,job和启动build等.显然地在大规模的公司需要多个部门一起协调工作的时候,没有任何安全检查会带来很多的问题. 在系统管理 ...

  9. centos jdk 下载

    wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com% ...

  10. js与jquery的动态加载脚本文件

    jquery动态加载 jQuery.getScript(url,[callback]) js动态加载 function loadJs(name) { document.write('<scrip ...