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求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小 ...
随机推荐
- Apache 配置HTTPS协议搭载SSL配置
在设置Apache + SSL之前, 需要做: 安装Apache, 请参见: Windows环境下Apache的安装与虚拟目录的配置, 下载安装Apache时请下载带有ssl版本的Apache ...
- 一天天的sql总结
一. 多张表之间的查询: join/inner join on inner join 是比较运算符,只返回符合条件的行. left/outer join on 左外连接包含left join左表所有 ...
- apache+tomcat分布式集群搭建
今天搭建apche+tomcat分布式集群,遇到很多问题,在网上找到的很多都不成功,然后和同事一起研究了一下,最终搭建成功了.做个笔记,以备自己以后参考. 1,下载apache.在下载Apache(2 ...
- LINQ to SQL快速上手 step by step
Step1:建立数据库 在使用Linq to Sql前,我们要将相应的数据库建好.在这个Demo中,使用的数据库是SQL Server Express 2005. 我们首先建立一个 ...
- druid的安装
最近想玩druid.druid的底层是fastbit索引的列式存储.采用分布式的zookeeper调度.实时大数据分析软件.主要针对OLAP操作. 搭环境搭环境.druid的核心成员成立了一个叫imp ...
- 编程范式 episode3 and 4,5
episode 3 --storage structure. ampersand operate with asterisk --library function episode 4 --generi ...
- LZW压缩算法
转载自http://www.cnblogs.com/jillzhang/archive/2006/11/06/551298.html 记录此处仅自己供学习之用 lzw解压缩算法: 用单个字符初始化字符 ...
- 测试table数据 winfrom datagridview 点击标头数字排序的时候table 列类型要为数字类型
public DataTable GenerateData(int NoOfRecord){DataTable tbl = new DataTable();tbl.Columns.Add(new Da ...
- 如何使用本地yum源?
首先为大家介绍在Centos系统上如何利用系统光盘/镜像作为yum源,实现程序包的安装等操作 1.首先在VM虚拟机上确保已载入光盘镜像,载入成功后显示如下效果. 2.挂载光盘镜像文件,使用命令: mo ...
- hdu4738 Caocao's Bridges
http://acm.hdu.edu.cn/showproblem.php?pid=4738 题目大意:曹操赤壁之战大败,于是卷土重来.为了避免水上作战,他在长江上建立了一些岛屿,这样他的士兵就可以在 ...