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求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小 ...
随机推荐
- 2016/12/14---- C3P0
查询查询一条记录 public UserBean findActiver(String ac) throws SQLException { QueryRunner qr = new QueryRunn ...
- findstr 命令
body { font-family: Bitstream Vera Sans Mono; font-size: 11pt; line-height: 1.5; } html, body { colo ...
- JQuery mobile 实例 api
http://www.w3school.com.cn/jquerymobile/jquerymobile_examples.asp
- 深入理解js——一切都是对象
"一切皆对象" 当然也不是所有的都是对象,值类型(undefined,number,string,boolean)就不是对象:而函数.对象.数组.null.new Number(1 ...
- Lua metatable & metamethod
[Lua metatable & metamethod] Lua中的每个值都有一套预定义的操作集合,比如数字是可以相加的,字符串是可以连接的,但是对于两个table类型,则不能直接进行“+”操 ...
- Delphi 7学习开发控件
我们知道使用Delphi快速开发,很大的一方面就是其强大的VCL控件,另外丰富的第三方控件也使得Delphi程序员更加快速的开发出所需要的程序.在此不特别介绍一些概念,只记录自己学习开发控件的步骤.假 ...
- python-函数中定义可变参数
可变参数 在Python函数中,还可以定义可变参数.顾名思义,可变参数就是传入的参数个数是可变的,可以是1个.2个到任意个,还可以是0个. 我们以数学题为例子,给定一组数字a,b,c……,请计算a2 ...
- iOS 发送Email
第一步:在程序中添加MessageUi.framework框架 第二步:引入#import <MessageUI/MessageUI.h>头文件 第三步:代码实现 3.1判断是否可以发送邮 ...
- 济南学习D2T2__数学分析题
[问题描述]有N个数,随机选择一段区间,如果这段区间的所有数的平均值在[l,r]中则你比较厉害.求你比较厉害的概率.[输入格式]第一行有三个数N,l,r,含义如上描述.接下来一行有N个数代表每一个数的 ...
- Java核心知识点学习----线程中如何创建锁和使用锁 Lock,设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...