bzoj 1977
题意:求严格的次小生成树。点n<=100000,m<=300000
思路:很容易想到先做一边最小生成树,然后枚举每条非树边(u, v, w),然后其实就是把u,v路径上小于w的最大边替换成w,对于所有的这种新树取一个权值最小的即可。。
然后就变成求u,v的最大值及次大值。。树链剖分和lct显然是可以做的。。
不过很早就知道倍增却一直没写过,今天就正好写一发。。
code:
/**************************************************************
Problem: 1977
User: yzcstca
Language: C++
Result: Accepted
Time:2344 ms
Memory:35048 kb
****************************************************************/ #include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<stack>
#include<ctime>
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define M0(x) memset(x, 0, sizeof(x))
#define vii vector< pair<int, int> >::iterator
#define x first
#define y second
#define two(i) (1 << i)
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = ;
const int maxm = ;
struct oo{
int u, v, w;
bool operator<(const oo& p) const{
return w < p.w;
}
} E[maxm];
vector<pii> e[maxn];
int fa[maxn], intree[maxm];
int n, m, ans;
int dep[maxn], f[maxn][], vv[maxn][][]; void init(){
for (int i = ; i < m; ++i)
scanf("%d%d%d", &E[i].u, &E[i].v, &E[i].w);
repf(i, , n) e[i].clear();
} inline int find(const int& k){
return fa[k] == k ? k : fa[k] = find(fa[k]);
} int vis[maxn], t[maxn];
void bfs(){
M0(vis);
queue<int> q;
q.push(), dep[] = , vis[] = ;
int u, v, cnt;
t[cnt = ] = ;
while (!q.empty()){
u = q.front();
q.pop();
for (vii it = e[u].begin(); it != e[u].end(); ++it){
if (vis[it->x]) continue;
dep[it->x] = dep[u] + ;
f[it->x][] = u;
vv[it->x][][] = it->y, vv[it->x][][] = -;
q.push(it->x), vis[it->x] = , t[++cnt] = it->x;
}
}
} void update(int v[],const int& val){
if (val > v[])
swap(v[], v[]), v[] = val;
else if (val < v[] && val > v[])
v[] = val;
} void rmq(){
int u, v;
repf(i, , n){
u = t[i];
for (int i = ; i <= ; ++i){
if (two(i) > dep[u]) break;
v = f[u][i-];
f[u][i] = f[v][i-];
vv[u][i][] = vv[u][i][] = -;
update(vv[u][i], vv[u][i-][]);
update(vv[u][i], vv[u][i-][]);
update(vv[u][i], vv[v][i-][]);
update(vv[u][i], vv[v][i-][]);
}
}
} int res[];
void query(int u, int s, int res[]){
for (int i = ; i <= ; ++i) if (s & two(i))
update(res, vv[u][i][]), update(res, vv[u][i][]), u = f[u][i], s ^= two(i);
} void work(int u, int v, const int& w){
if (dep[u] > dep[v]) swap(u, v);
int fu = u, fv = v, h;
if (dep[fu] != dep[fv]){
h = dep[fv] - dep[fu];
for (int i = ; i <= ; ++i) if (h & two(i))
h ^= two(i), fv = f[fv][i];
}
if (fu == fv){
res[] = res[] = -;
query(v, dep[v] - dep[u], res);
h = (res[] != w) ? res[] : res[];
if (h != -) ans = min(ans, w - h);
return;
}
for (int i = ; i >= ; --i){
if (two(i) > dep[fu]) continue;
if (f[fu][i] != f[fv][i])
fu = f[fu][i], fv = f[fv][i];
}
fu = f[fu][];
res[] = res[] = -;
query(u, dep[u] - dep[fu], res);
query(v, dep[v] - dep[fu], res);
h = (res[] != w) ? res[] : res[];
if (h != -) ans = min(ans, w - h);
} void solve(){
repf(i, , n) fa[i] = i;
sort(E, E + m);
memset(intree, , sizeof(int) * (m + ));
int u, v, fu, fv, w;
ll mst = ;
repf(i, , m-){
u = E[i].u, v = E[i].v, w = E[i].w;
fu = find(u), fv = find(v);
if (fu != fv){
fa[fu] = fv, intree[i] = ;
mst += E[i].w;
e[u].push_back(make_pair(v, w));
e[v].push_back(make_pair(u, w) );
}
}
bfs();
rmq();
ans = 0x3fffffff;
for (int i = ; i < m; ++i) if (!intree[i])
work(E[i].u, E[i].v, E[i].w);
cout << mst + ans << endl; } int main(){
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
while (scanf("%d%d", &n, &m) != EOF){
init();
solve();
}
return ;
}
bzoj 1977的更多相关文章
- BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...
- bzoj 1977 [BeiJing2010组队]次小生成树 Tree
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977 kruscal别忘了先按边权sort.自己觉得那部分处理得还挺好的.(联想到之前某题的 ...
- [BeiJing2010组队][BZOJ 1977]次小生成树 Tree
话说这个[BeiJing2010组队]是个什喵玩意? 这是一道严格次小生成树,而次小生成树的做法是层出不穷的 MATO IS NO.1 的博客里对两种算法都有很好的解释,值得拥有: (果然除我以外, ...
- BZOJ 1977 次小生成树
TM终于过了.... #include<iostream> #include<cstdio> #include<cstring> #include<algor ...
- BZOJ 1977 次小生成树(最近公共祖先)
题意:求一棵树的严格次小生成树,即权值严格大于最小生成树且权值最小的生成树. 先求最小生成树,对于每个不在树中的边,取两点间路径的信息,如果这条边的权值等于路径中的权值最大值,那就删掉路径中的次大值, ...
- BZOJ 1977 严格次小生成树(算竞进阶习题)
树上倍增+kruskal 要找严格次小生成树,肯定先要找到最小生成树. 我们先把最小生成树的边找出来建树,然后依次枚举非树边,容易想到一种方式: 对于每条非树边(u,v),他会与树上的两个点构成环,我 ...
- BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树
描述: 就是求一个次小生成树的边权和 传送门 题解 我们先构造一个最小生成树, 把树上的边记录下来. 然后再枚举每条非树边(u, v, val),在树上找出u 到v 路径上的最小边$g_0$ 和 严格 ...
- 【刷题】BZOJ 1977 [BeiJing2010组队]次小生成树 Tree
Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...
- BZOJ 1977 严格次小生成树
小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小 ...
随机推荐
- 三层VS控制器
三层中的Model 是数据模型 与数据库字段一一对应而mvc中的model是 显示模型,指在页面的显示字段的列一一对应,不一定在数据库中有这样的一个表,如当页 面上要显示多个表的综合信息时. 当在Co ...
- jquery radio取值,checkbox取值,select取值及选中
jquery radio取值,checkbox取值,select取值,radio选中,checkbox选中,select选中,及其相关 获取一组radio被选中项的值 var item = $('in ...
- 简洁既是美—用while语句复制数组
简洁既是美,程序员应尽量尝试编写简洁的表达式,争取用简单的代码来实现更多的功能,当然,这也要看情况了(有时候也得考虑程序运行的时间嘛). 在阅读C++Prime Plus到while语句时有一个讲一个 ...
- angular笔记
/** * Created by Administrator on 2016/5/3 0003. */ ng-app是告诉angularjs编译器把该元素当作编译的根 //定义模块 var myApp ...
- 记录今天学习python中for与while循环针对break和continue的用法
python中有两个主要的循环for与while,其中针对这两个循环有两种不同的中断用法break与continue. 首先先看下面的循环代码: 1: for i in range(10):#变量i带 ...
- 在C#中创建和读取XML文件
1.创建简单的XML文件 为了便于测试,我们首先创建控制台应用程序,项目命名为CreateXml,Program.cs代码如下: 这样会在C盘根目录下创建data2.xml文件,文件内容为 using ...
- LeetCode OJ 150. Evaluate Reverse Polish Notation
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, ...
- C盘实际占用容量比显示的要少
1.问题 服务器是Window Server 2008 R2,就几天时间,60G的C盘容量一下子满了,选中所有的文件,占用才20多G. 2.原因 1).有的文件没有系统管理员权限,大小不会显示出来. ...
- JSP页面数据展示:分组数据展示
一.描述: 页面上要展示的数据只要写好sql从数据库查出来即可,但是展示有时候不是太好处理.比如工作中遇到的这种情况:有一个问题处理的流程,其中需要选择下一处理人,这些处理人要以部门的形式分组展示,实 ...
- 团队项目作业:利用NABCD模型进行竞争性需求分析
NABC正是这样的一套框架,当你试图提出一项崭新的提案之际,它能够提供四个思维基点,令你的商业策划具备天马行空的基础. 具体来说,NABC是四个关键词的首字母缩写- Need(需求)-现在市场上未被满 ...