1977: [BeiJing2010组队]次小生成树 Tree

https://lydsy.com/JudgeOnline/problem.php?id=1977

题意:

  求严格次小生成树,即边权和不能等于最小生成树。

分析:

  倍增:求出最小生成树,然后枚举非树边,加入一条非树边,删掉环上的最大的边,如果最大的边等于加入的边,那么删掉环上次小的边。

  LCT:直接维护链上最大值,与次大值。

代码:

倍增

 #include<bits/stdc++.h>
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for (;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
const int M = ;
const LL INF = 1e18; struct Edge{
int u,v,w;
bool operator < (const Edge &A) const {
return w < A.w;
}
}e[M];
int head[N],nxt[N<<],to[N<<],Enum;
int fa[N],deth[N],f[N][];
LL g1[N][],g2[N][],val[N<<],Sum;
bool used[M]; //------ used[N] inline void add_edge(int u,int v,int w) {
++Enum; to[Enum] = v; val[Enum] = w; nxt[Enum] = head[u]; head[u] = Enum;
++Enum; to[Enum] = u; val[Enum] = w; nxt[Enum] = head[v]; head[v] = Enum;
}
void dfs(int u,int fa) {
deth[u] = deth[fa] + ;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
if (v == fa) continue; // 写在下面了。。。
f[v][] = u;
g1[v][] = val[i]; // -- e[i].w
g2[v][] = -INF;
dfs(v,u);
}
}
inline void get(LL a,LL b,LL &mx1,LL &mx2) {
if (a > mx1) mx2 = max(mx1,b);
else if (a == mx1) mx2 = max(mx2, b);
else if (a < mx1) mx2 = max(mx2, a);
mx1 = max(mx1,a);
}
inline LL solve(int u,int v,int w) {
if (deth[u] < deth[v]) swap(u,v);
int d = deth[u] - deth[v];
LL mx1 = -INF, mx2 = -INF;
for (int i=; i>=; --i) {
if (d & ( << i)) {
get(g1[u][i],g2[u][i],mx1,mx2);
u = f[u][i];
}
}
if (u == v) return Sum + w - (mx1 < w ? mx1 : mx2);
for (int i=; i>=; --i) {
if (f[u][i] != f[v][i]) { // -- f[u][i]==f[u][i]
get(g1[u][i],g2[u][i],mx1,mx2);
get(g1[v][i],g2[v][i],mx1,mx2);
u = f[u][i], v = f[v][i];
}
}
get(g1[u][],g2[u][],mx1,mx2);
get(g1[v][],g2[v][],mx1,mx2);
return Sum + w - (mx1 < w ? mx1 : mx2);
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
int main() { int n = read(),m = read();
for (int i=; i<=m; ++i) {
e[i].u = read(), e[i].v = read(), e[i].w = read();
}
sort(e+,e+m+);
for (int i=; i<=n; ++i) fa[i] = i;
int cnt = ;
for (int i=; i<=m; ++i) {
int u = find(e[i].u), v = find(e[i].v);
if (u != v) {
used[i] = true;
add_edge(e[i].u,e[i].v,e[i].w);
fa[u] = v;
Sum += e[i].w;
cnt++;
if (cnt == n-) break;
}
}
dfs(,);
for (int j=; j<=; ++j)
for (int i=; i<=n; ++i) {
int k = f[i][j-];
LL a1 = g1[i][j-], a2 = g1[k][j-];
LL b1 = g2[i][j-], b2 = g2[k][j-];
f[i][j] = f[k][j-];
g1[i][j] = max(a1, a2);
if (a1 == a2) g2[i][j] = max(b1, b2);
else {
g2[i][j] = min(a1, a2);
g2[i][j] = max(g2[i][j], max(b1, b2)); //---
}
}
LL Ans = INF; // -- ANs = Sum
for (int i=; i<=m; ++i) {
if (!used[i])
Ans = min(Ans, solve(e[i].u,e[i].v,e[i].w));
}
cout << Ans;
return ;
}

LCT

 #include<bits/stdc++.h>
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for (;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
const int M = ; struct Edge{
int u,v,w;
bool operator < (const Edge &A) const {
return w < A.w;
}
}e[M];
int fa[N<<],ch[N<<][],fir[N<<],sec[N<<],rev[N<<],sk[N<<],Top;
LL val[N<<];
int p[N]; bool isroot(int x) {
return ch[fa[x]][] != x && ch[fa[x]][] != x;
}
int son(int x) {
return ch[fa[x]][] == x;
}
void pushup(int x) {
int lc = ch[x][], rc = ch[x][];
if (fir[lc] > fir[rc]) fir[x] = fir[lc], sec[x] = max(sec[lc], fir[rc]);
else if (fir[lc] < fir[rc]) fir[x] = fir[rc], sec[x] = max(sec[rc], fir[lc]);
else fir[x] = fir[lc], sec[x] = max(sec[lc], sec[rc]); if (val[x] > fir[x]) sec[x] = fir[x], fir[x] = val[x];
else if (val[x] < fir[x] && val[x] > sec[x]) sec[x] = val[x];
}
void pushdown(int x) {
if (rev[x]) {
rev[ch[x][]] ^= , rev[ch[x][]] ^= ;
swap(ch[x][], ch[x][]);
rev[x] ^= ;
}
}
void rotate(int x) {
int y = fa[x],z = fa[y],b = son(x),c = son(y),a = ch[x][!b];
if (!isroot(y)) ch[z][c] = x; fa[x] = z;
ch[x][!b] = y;fa[y] = x;
ch[y][b] = a; if (a) fa[a] = y;
pushup(y); pushup(x);
}
void splay(int x) {
sk[Top = ] = x;
for (int i=x; !isroot(i); i=fa[i]) sk[++Top] = fa[i];
while (Top) pushdown(sk[Top--]);
while (!isroot(x)) {
int y = fa[x];
if (isroot(y)) rotate(x);
else {
if (son(x) == son(y)) rotate(y), rotate(x);
else rotate(x), rotate(x);
}
}
}
void access(int x) {
for (int last=; x; last=x,x=fa[x]) {
splay(x); ch[x][] = last; pushup(x);
}
}
void makeroot(int x) {
access(x); splay(x); rev[x] ^= ;
}
int find(int x) {
return x == p[x] ? x : p[x] = find(p[x]);
} int main() {
int n = read(),m = read(),Index = n;
for (int i=; i<=n; ++i) p[i] = i;
for (int i=; i<=m; ++i) {
e[i].u = read(), e[i].v = read(), e[i].w = read();
}
sort(e+,e+m+);
LL Sum = , Ans = 1e18;
for (int i=; i<=m; ++i) {
int x = e[i].u, y = e[i].v;
int u = find(x), v = find(y);
if (u != v) {
makeroot(x);
fa[x] = ++Index; // 化边权为点权
fa[Index] = y;
fir[Index] = val[Index] = e[i].w;
Sum += e[i].w;
p[u] = v;
}
else {
makeroot(x);
access(y);
splay(y);
Ans = min(Ans, (LL)e[i].w - (e[i].w > fir[y] ? fir[y] : sec[y]));
}
}
cout << Ans + Sum;
return ;
}

upd:2018.10.22

前几天模拟赛出了这道题,考试的时候写的,感觉比以前的好写些。

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define fi(s) freopen(s,"r",stdin);
#define fo(s) freopen(s,"w",stdout);
using namespace std;
typedef long long LL; char buf[], *p1 = buf, *p2 = buf;
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
inline int read() {
int x=,f=;char ch=nc();for(;!isdigit(ch);ch=nc())if(ch=='-')f=-;
for(;isdigit(ch);ch=nc())x=x*+ch-'';return x*f;
} const int N = ;
const int LOG = ; struct Edge{
int u, v; LL w;
bool operator < (const Edge &A) const {
return w < A.w;
}
}e[N * ], R[N * ]; struct ST{
int x;LL mx, ci;
ST() { x = mx = ci = ; }
}f[N][];
int head[N], to[N * ], nxt[N * ]; LL len[N * ];
int fa[N], deth[N];
int n, m, En, tot; LL Sum; ST operator + (const ST &A, const ST &B) {
ST res; res.x = B.x;
if (A.mx > B.mx) res.mx = A.mx, res.ci = max(A.ci, B.mx);
else if (B.mx > A.mx) res.mx = B.mx, res.ci = max(A.mx, B.ci);
else res.mx = A.mx, res.ci = max(A.ci, B.ci);
return res;
} inline void add_edge(int u,int v,LL w) {
++En; to[En] = v; len[En] = w; nxt[En] = head[u]; head[u] = En;
++En; to[En] = u; len[En] = w; nxt[En] = head[v]; head[v] = En;
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void Kruskal() {
sort(e + , e + m + );
for (int i=; i<=n; ++i) fa[i] = i;
for (int i=; i<=m; ++i) {
int u = find(e[i].u), v = find(e[i].v);
if (u != v) {
fa[u] = v; Sum += e[i].w;
add_edge(e[i].u, e[i].v, e[i].w);
}
else R[++tot] = e[i];
}
} void dfs(int u,int pa) {
deth[u] = deth[pa] + ;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
if (v == pa) continue;
dfs(v, u);
f[v][].x = u;
f[v][].mx = len[i];
}
} void D(const ST &A) {
cerr << A.x << " " << A.mx << " " << A.ci << "\n";
} ST work(int u,int v) {
ST ans; //ans.mx = -1; ans.ci = -1; ans.x = 0;
if (deth[u] < deth[v]) swap(u, v);
int d = deth[u] - deth[v];
for (int j=LOG; j>=; --j) {
if ((d >> j) & ) {
ans = ans + f[u][j]; // 顺序!!!
u = f[u][j].x;
// D(ans);
}
}
if (u == v) return ans;
for (int j=LOG; j>=; --j) {
if (f[u][j].x != f[v][j].x) {
ans = ans + f[u][j]; ans = ans + f[v][j];
u = f[u][j].x, v = f[v][j].x;
// D(ans);
}
}
return ans + f[u][] + f[v][];
} int main() { //fi("2.txt"); // freopen("tree.in","r",stdin);
// freopen("tree.out","w",stdout); n = read(), m = read();
for (int i=; i<=m; ++i)
e[i].u = read(), e[i].v = read(), e[i].w = read();
sort(e + , e + m + );
Kruskal();
dfs(, ); for (int j=; j<=LOG; ++j)
for (int i=; i<=n; ++i)
f[i][j] = f[i][j - ] + f[f[i][j - ].x][j - ]; ST now;
LL Ans = 1e18;
for (int i=; i<=tot; ++i) {
now = work(R[i].u, R[i].v);
if (R[i].w != now.mx) Ans = min(Ans, Sum - now.mx + R[i].w);
else if (now.ci) Ans = min(Ans, Sum - now.ci + R[i].w);
}
cout << Ans;
return ;
}

1977: [BeiJing2010组队]次小生成树 Tree的更多相关文章

  1. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )

    做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...

  2. BZOJ 1977[BeiJing2010组队]次小生成树 Tree - 生成树

    描述: 就是求一个次小生成树的边权和 传送门 题解 我们先构造一个最小生成树, 把树上的边记录下来. 然后再枚举每条非树边(u, v, val),在树上找出u 到v 路径上的最小边$g_0$ 和 严格 ...

  3. 【刷题】BZOJ 1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

  4. bzoj 1977 [BeiJing2010组队]次小生成树 Tree

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1977 kruscal别忘了先按边权sort.自己觉得那部分处理得还挺好的.(联想到之前某题的 ...

  5. BZOJ 1977: [BeiJing2010组队]次小生成树 Tree 倍增 最小生成树

    好吧我太菜了又调了一晚上...QAQ 先跑出最小生成树,标记树边,再用树上倍增的思路,预处理出: f[u][i] :距离u为2^i的祖先 h[u][i][0/1] :距u点在2^i范围内的最长边和次长 ...

  6. [BeiJing2010组队]次小生成树 Tree

    1977: [BeiJing2010组队]次小生成树 Tree Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 5168  Solved: 1668[S ...

  7. 【BZOJ1977】[BeiJing2010组队]次小生成树 Tree 最小生成树+倍增

    [BZOJ1977][BeiJing2010组队]次小生成树 Tree Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C ...

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

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

  9. 【次小生成树】bzoj1977 [BeiJing2010组队]次小生成树 Tree

    Description 小 C 最近学了很多最小生成树的算法,Prim 算法.Kurskal 算法.消圈算法等等. 正当小 C 洋洋得意之时,小 P 又来泼小 C 冷水了.小 P 说,让小 C 求出一 ...

随机推荐

  1. Android进阶笔记12:ListView篇之图片优化

    1.图片异步加载: (1)处理图片的方式: 如果ListView中自定义的Item中有涉及到大量图片的,一定要对图片进行细心的处理,因为图片占的内存是 ListView 项中最头疼的,处理图片的方法大 ...

  2. 【[ZJOI2014]力】

    题目 好神仙啊 \[F_{j}=\sum_{i<j}\frac{q_iq_j}{(i-j)^2}-\sum_{j<i}\frac{q_iq_j}{(i-j)^2}\] 求\(\frac{F ...

  3. PAML学习一

    前言 模式识别起源于工程,而机器学习从计算机科学中产生.然而这两者被看做同一领域的两方面,过去十年里他们获得了极大的发展.特别是,贝叶斯方法已经发展成主流,而图模型已经被融入用于描述和应用概率模型的通 ...

  4. 【luogu P2746 [USACO5.3]校园网Network of Schools】 题解

    题目链接:https://www.luogu.org/problemnew/show/P2812 注意:判断出入度是否为0的时候枚举只需到颜色的数量. 坑点:当只有一个强连通分量时,不需要再添加新边. ...

  5. js通过ua标识判断h5页面是否内嵌在app内

    var userAgent = navigator.userAgent.toLowerCase();//获取UA信息 if(userAgent.indexOf("ezhouxing" ...

  6. JDBC连接数据库时错误提示的解决方案汇总

    今天在连接JDBC时,出现了错误 最开始的URL是这样写的 Connection conn = DriverManager.getConnection("jdbc:mysql://local ...

  7. Openresty最佳案例 | 第5篇:http和C_json模块

    转载请标明出处: http://blog.csdn.net/forezp/article/details/78616672 本文出自方志朋的博客 http客户端 Openresty没有提供默认的Htt ...

  8. Python 学习笔记(八)Python列表(二)

    列表函数 追加和扩展 list.append() 在列表末尾追加新的对象 >>> dir(list) #dir 查看列表的函数 ['__add__', '__class__', '_ ...

  9. xcode 快捷键大全、XCode常用快捷键图文介绍

    其实就是设置里面的快捷键变成了文字版,刚开始用Xcode是不是发现以前熟悉的开发环境的快捷键都不能用了?怎么快捷运行,停止,编辑等等.都不一样了.快速的掌握这些快捷键,能提供开发的效率. 其实快捷键在 ...

  10. FastJson反序列化漏洞利用的三个细节 - TemplatesImpl的利用链

    0. 前言 记录在FastJson反序列化RCE漏洞分析和利用时的一些细节问题. 1. TemplatesImpl的利用链 关于 parse 和 parseObject FastJson中的 pars ...