BZOJ1977 (严格)次小生成树
来源:互联网 发布:python中return的用法 编辑:程序博客网 时间:2024/05/18 01:07
(同步个人博客 http://sxysxy.org/blogs/30 到 csdn)
题目见http://www.lydsy.com/JudgeOnline/problem.php?id=1977 权限题不过还可以在http://cojs.tk/cogs/problem/problem.php?pid=2453 提交
求一张无向图的严格次小生成树,严格次小就是权值之和严格小于最小生成树。
首先构造最小生成树,然后尝试用不在最小生成树里的边替换掉最小生成树中的某条边,得到新的生成树,取其权值和最小值。我一开始随手写了个kruskal求最小生成树,然后树链剖分+线段树维护树链上的最大值,之后对于每条不在最小生成树的边e,当e.value > e.from到e.to树链上权值最大边的权值时,用e替换e.from到e.to树链上权值最大的边,依次进行这样的操作,最后得到权值最小的生成树为答案。感觉还是很水很水的。
然而WA了 QAQ
经过Fmuckss 神犇的指导,才忽然明白,用Kruskal求到的虽然的确是最小生成树,但得到并不是唯一的最小生成树(也有可能存在其他形态但权值和也是最小值的最小生成树)。于是试图替换这个不是唯一的那个最小生成树就WA了。
但是难道真的要枚举出来所有最小生成树的形态吗?显然会TLE的。
然后看了下cojs上某神犇(qaq我不认识)的代码,豁然明朗:维护树链的线段树不仅维护区间最大值,同时再维护区间第二大值。这样还是刚才的套路,只是最后在尝试替换最小生成树里面的边时,如果用来替换的边e的权值与原来e.from, e.to上树链权值最大边的权值相等时,应该替换[e.from, to]上权值第二大的边。这就解决问题了。
这个题要用long long啊要用long long...
代码:(在cojs与bzoj上都ac辣):
#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <iostream>#include <algorithm>#include <list>#include <vector>#include <set>using namespace std;struct edge{ int from, to; int value; bool intree; bool operator<(const edge &oe) const { return value < oe.value; }};#define MAXN 100022#define MAXM 300012edge edges[MAXM];int uniset[MAXN];int pa(int x){ return x == uniset[x]?x: uniset[x] = pa(uniset[x]);}long long maketree(int n, int m){ int cnt = 0; for(int i = 1; i <= n; i++) uniset[i] = i; long long tot = 0; for(int i = 1; i <= m; i++) { edge &e = edges[i]; int a = pa(e.from); int b = pa(e.to); if(a != b) { tot += e.value; uniset[a] = b; e.intree = true; cnt++; if(cnt == n-1)return tot; } } return tot;}vector<int> G[MAXN];int top[MAXN];int deep[MAXN];int parent[MAXN];int son[MAXN];int size[MAXN];void dfs1(int u, int f, int d){ parent[u] = f; size[u] = 1; deep[u] = d; son[u] = 0; for(int i = 0; i < G[u].size(); i++) { int to = G[u][i]; if(to != f) { dfs1(to, u, d+1); size[u] += size[to]; if(size[to] > size[son[u]]) son[u] = to; } }}int has[MAXN];int hasid = 1;void dfs2(int u, int tp){ top[u] = tp; has[u] = hasid++; if(!son[u])return; dfs2(son[u], tp); for(int i = 0; i < G[u].size(); i++) { int to = G[u][i]; if(to != parent[u] && to != son[u]) dfs2(to, to); }}//线段树维护两点之间权值最大值int val[MAXN];struct node{ int l, r; int ls, rs; int maxv; int secv;}ns[MAXN<<1];int root = 1;int last = root;void pushup(int c){ if(c) { node &d = ns[c]; d.maxv = max(ns[d.ls].maxv, ns[d.rs].maxv); if(ns[d.ls].maxv < ns[d.rs].maxv) d.secv = max(ns[d.rs].secv, ns[d.ls].maxv); else if(ns[d.ls].maxv > ns[d.rs].maxv) d.secv = max(ns[d.rs].maxv, ns[d.ls].secv); else d.secv = max(ns[d.ls].secv, ns[d.rs].secv); }}int build(int l, int r){ int cur = last++; node &d = ns[cur]; d.l = l; d.r = r; int m = (l+r)>>1; if(l == r) { d.maxv = val[l]; d.secv = -0x6eafbae; return cur; } if(l <= m) { d.ls = build(l, m); d.rs = build(m+1, r); pushup(cur); return cur; }else return 0;}int querytree(int c, int l, int r, int v){ if(!c)return -1; node &d = ns[c]; if(d.l == l && r == d.r)return d.maxv == v? d.secv:d.maxv; else if(l >= ns[d.rs].l)return querytree(d.rs, l, r, v); else if(r <= ns[d.ls].r)return querytree(d.ls, l, r, v); else return max(querytree(d.ls, l, ns[d.ls].r, v), querytree(d.rs, ns[d.rs].l, r, v));}int querymax(int u, int v, int w){ int ans = -1; int t1 = top[u], t2 = top[v]; while(t1 != t2) { if(deep[t1] < deep[t2]) { swap(t1, t2); swap(u, v); } ans = max(ans, querytree(root, has[t1], has[u], w)); u = parent[t1]; t1 = top[u]; } if(u == v)return ans; else { if(deep[u] < deep[v])swap(u, v); ans = max(ans, querytree(root, has[son[v]], has[u], w)); return ans; }}int nexte[MAXN]; //保存在最小生成树里面的边,加快速度int main(){ //freopen("secmst.in", "r", stdin); //freopen("secmst.out", "w", stdout); int n, m; scanf("%d %d", &n, &m); for(int i = 1; i <= m; i++) { edge &e = edges[i]; e.intree = false; scanf("%d %d %d", &e.from, &e.to, &e.value); } sort(edges+1, edges+m+1); //构造最小生成树 long long mtreev = maketree(n, m); int pn = 1; for(int i = 1; i <= m; i++) { edge &e = edges[i]; if(e.intree) { G[e.from].push_back(e.to); G[e.to].push_back(e.from); nexte[pn++] = i; } } //剖分 dfs1(1, 0, 0); dfs2(1, 1); //建线段树 for(int i = 1; i < pn; i++) { edge &e = edges[nexte[i]]; if(deep[e.from] > deep[e.to]) val[has[e.from]] = e.value; else val[has[e.to]] = e.value; } build(1, hasid-1); //找次小生成树 long long ans = 0x7fffffffffffffff; for(int i = 1; i <= m; i++) { edge &e = edges[i]; if(!e.intree) { long long tmp = e.value - querymax(e.from, e.to, e.value); ans = min(tmp, ans); } } printf("%lld\n", mtreev + ans); return 0;}
- 【BZOJ1977】【BJOI2011】严格次小生成树
- BZOJ1977 (严格)次小生成树
- bzoj1977 严格的次小生成树(LCA倍增)
- [BZOJ1977]严格次小生成树-kruskal+倍增维护
- bzoj1977次小生成树
- 【bzoj1977】【严格次小生成树】倍增维护链上最大次大值
- 【bzoj1977】【次小生成树】【树上倍增】
- bzoj1977 次小生成树【最小生成树+倍增】
- [BZOJ1977][Beijing2010组队][LCA][Kruskal]次小生成树
- bzoj1977: [BeiJing2010组队]次小生成树 Tree
- bzoj1977: [BeiJing2010组队]次小生成树 Tree
- BZOJ1977: [BeiJing2010组队]次小生成树 Tree
- bzoj1977 [BeiJing2010组队]次小生成树 Tree
- BZOJ1977: [BeiJing2010组队]次小生成树 Tree
- bzoj1977: [BeiJing2010组队]次小生成树 Tree 树上倍增
- bzoj1977 [BeiJing2010组队]次小生成树 倍增
- bzoj1977 [BeiJing2010组队]次小生成树 Tree (lca+倍增)
- bzoj1977 [BeiJing2010]次小生成树 Tree(kruskal+树上倍增)
- Eclipse中server启动超时的解决方法
- 算法学习
- React 数据流与状态控制-props与sate的区别
- 文章标题
- SVN的配置及简单使用
- BZOJ1977 (严格)次小生成树
- L1-013. 计算阶乘和-PAT团体程序设计天梯赛GPLT
- 《GPU高性能编程CUDA实战》学习笔记(五)
- JAVA-最最最最基础的一些知识,你知道吗?
- SSL在tomcat上的配置,nginx上的简单配置。及其注意事项
- PAT 1061. Dating (20)(按一定规则找俩个字符串中相同的字符)(待修改)
- 让更多的人知道如何用C#操作斑马条码打印机
- 安卓入门--四大组件--Service高级用法
- 幻方构造模版