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. HDU 4757 Tree(可持续化字典树,lca)

    题意:询问树上结点x到结点y路上上的权值异或z的最大值. 任意结点权值 ≤ 2^16,可以想到用字典树. 但是因为是询问某条路径上的字典树,将字典树可持续化,字典树上的结点保存在这条路径上的二进制数. ...

  2. Android(java)学习笔记46:反射机制

    1. 反射机制: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称 ...

  3. Android(java)学习笔记27:TextView属性大全

    TextView属性大全: android:autoLink       设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web/email/ph ...

  4. android 中组件继承关系图,一目了然

    View继承关系图 Adapter适配器继承关系图 Activity继承关系图

  5. ACM-ICPC 2017 Asia HongKong 解题报告

    ACM-ICPC 2017 Asia HongKong 解题报告 任意门:https://nanti.jisuanke.com/?kw=ACM-ICPC%202017%20Asia%20HongKon ...

  6. 应用性能指数(APDEX)是如何计算出来的?

    应用性能指数(APDEX)是如何计算出来的?在应用性能管理领域聚合指标是一种常见手段,主要是用来把成百上千的指标通过某种计算方法聚合成一个或几个指标,用来反映应用的整体健康状态.在这些聚合指标中,比较 ...

  7. L1 loss L2 loss

    https://www.letslearnai.com/2018/03/10/what-are-l1-and-l2-loss-functions.html http://rishy.github.io ...

  8. tomcate8配置多个二级域名问题解决根目录空白2017年12月9日

    <Host name="localhost" appBase="webapps" unpackWARs="true" autoDepl ...

  9. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--G-旋转矩阵

    链接:https://www.nowcoder.com/acm/contest/90/G 来源:牛客网 1.题目描述 景驰公司自成立伊始,公司便将“推动智能交通的发展,让人类的出行更安全,更高效,更经 ...

  10. C#判断系统是64位还是32位 支持.net4.0以前的版本

    C#判断系统是64位还是32位的时候引用了一串代码,这个代码是从园子里面其他博文中转载过来的,引入自己的项目中发现无法使用,在引用了相应的命名空间之后还是提示: "未能找到类型或命名空间名称 ...