一道LCA+生成树

BZOJ原题链接

洛谷原题链接

细节挺多,我调了半天。。累炸。。

回到正题,我们先求出随便一棵最小生成树(设边权和为\(s\)),然后扫描剩下所有边,设扫到的边的两端点为\(x,y\),长度为\(z\),树上\(x,y\)间边权最大的边和严格次大的边分别为\(dis_1,dis_2\)。

如果\(z>dis_1\),那么这条边可以替换掉\(dis_1\)对应的边,则得到一个可能答案\(s-dis_1+z\)。

如果\(z=dis_1\),那么这条边可以替换掉\(dis_2\)对应的边,则得到一个可能答案\(s-dis_2+z\)。

然后我们就可以用倍增\(LCA\)快速求树上\(x,y\)间边权最大的边和严格次大的边,定义数组\(g[x][k][0],g[x][k][1]\)表示从节点\(x\)往上跳\(2^k\)下所经过的路径的最大值和严格次小值,然后在预处理\(LCA\)的同时处理即可。

因为调到心态爆炸,所以代码可能比较丑。。

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int M = 3e5 + 10;
const int K = 17;
struct dd {
int x, y, z;
};
dd a[M];
struct aw {
int ma, se_ma;
aw()
{
ma = se_ma = 0;
}
};
int fi[N], di[N << 1], da[N << 1], ne[N << 1], f[N][K], g[N][K][2], de[N], fa[N], l, gn;
bool v[M];
int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c<'0' || c>'9'; c = getchar())
p |= c == '-';
for (; c >= '0'&&c <= '9'; c = getchar())
x = x * 10 + (c - '0');
return p ? -x : x;
}
int comp(dd x, dd y)
{
return x.z < y.z;
}
inline void sw(int &x, int &y)
{
int z = x;
x = y;
y = z;
}
inline int maxn(int x, int y)
{
return x > y ? x : y;
}
inline ll minn(ll x, ll y)
{
return x < y ? x : y;
}
inline int fin(int x)
{
if (!(fa[x] ^ x))
return x;
return fa[x] = fin(fa[x]);
}
inline void add(int x, int y, int z)
{
di[++l] = y;
da[l] = z;
ne[l] = fi[x];
fi[x] = l;
}
void dfs(int x)
{
int i, y;
for (i = 1; i <= gn; i++)
{
f[x][i] = f[f[x][i - 1]][i - 1];
g[x][i][0] = maxn(g[x][i - 1][0], g[f[x][i - 1]][i - 1][0]);
g[x][i][1] = !(g[x][i - 1][0] ^ g[f[x][i - 1]][i - 1][0]) ? maxn(g[x][i - 1][1], g[f[x][i - 1]][i - 1][1]) : (g[x][i - 1][0] > g[f[x][i - 1]][i - 1][0]) ? maxn(g[x][i - 1][1], g[f[x][i - 1]][i - 1][0]) : maxn(g[x][i - 1][0], g[f[x][i - 1]][i - 1][1]);
}
for (i = fi[x]; i; i = ne[i])
{
y = di[i];
if (!de[y])
{
de[y] = de[x] + 1;
f[y][0] = x;
g[y][0][0] = da[i];
g[y][0][1] = -1e9;
dfs(y);
}
}
}
aw fx(aw X, int i, int x)
{
if (X.ma < g[x][i][0])
{
X.se_ma = maxn(X.ma, g[x][i][1]);
X.ma = g[x][i][0];
}
else
if (X.ma > g[x][i][0])
X.se_ma = maxn(g[x][i][0], g[x][i][1]);
return X;
}
aw lca(int x, int y)
{
int i;
aw X;
if (de[x] > de[y])
sw(x, y);
for (i = gn; ~i; i--)
if (de[f[y][i]] >= de[x])
{
X = fx(X, i, y);
y = f[y][i];
}
if (!(x^y))
return X;
for (i = gn; ~i; i--)
if (f[x][i] ^ f[y][i])
{
X = fx(X, i, x);
X = fx(X, i, y);
x = f[x][i];
y = f[y][i];
}
X = fx(X, 0, x);
return X;
}
int main()
{
int i, k = 0, n, m, x, y;
ll s = 0, mi = 1e18;
n = re();
m = re();
gn = log2(n);
for (i = 1; i <= n; i++)
fa[i] = i;
for (i = 1; i <= m; i++)
{
a[i].x = re();
a[i].y = re();
a[i].z = re();
}
sort(a + 1, a + m + 1, comp);
for (i = 1; i <= m; i++)
{
x = fin(a[i].x);
y = fin(a[i].y);
if (x^y)
{
fa[y] = x;
k++;
s += a[i].z;
add(a[i].x, a[i].y, a[i].z);
add(a[i].y, a[i].x, a[i].z);
v[i] = 1;
}
if (!(k ^ (n - 1)))
break;
}
de[1] = 1;
dfs(1);
aw X;
for (i = 1; i <= m; i++)
if (!v[i])
{
X = lca(a[i].x, a[i].y);
if (!(a[i].z^X.ma))
mi = minn(mi, s - X.se_ma + a[i].z);
else
mi = minn(mi, s - X.ma + a[i].z);
}
printf("%lld", mi);
return 0;
}

BZOJ1977或洛谷4180 [BJWC2010]次小生成树的更多相关文章

  1. 洛谷P4180 [BJWC2010]次小生成树(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

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

  2. 洛谷.4180.[模板]次小生成树Tree(Kruskal LCA 倍增)

    题目链接 构建完MST后,枚举非树边(u,v,w),在树上u->v的路径中找一条权值最大的边(权为maxn),替换掉它 这样在 w=maxn 时显然不能满足严格次小.但是这个w可以替换掉树上严格 ...

  3. bzoj 1977 洛谷P4180 严格次小生成树

    Description: 给定一张N个节点M条边的无向图,求该图的严格次小生成树.设最小生成树边权之和为sum,那么严格次小生成树就是边权之和大于sum的最小的一个 Input: 第一行包含两个整数N ...

  4. 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)

    洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...

  5. luogu 4180 严格次小生成树

    次小生成树,顾名思义和次短路的思路似乎很类似呀, 于是就先写了个kruskal(prim不会)跑出最小生成树,给所有路径打标记,再逐个跑最小生成树取大于最小生成树的最小值 50分 #include&l ...

  6. 洛咕P4180 严格次小生成树

    鸽了很久的一道题(?)貌似是去年NOIP前听的emm... 首先我们分析一下最小生成树的性质 我们kruskal建树的时候呢是从小到大贪心加的边,这个的证明用到拟阵.(我太菜了不会) 首先我们不存在连 ...

  7. [洛谷P4341][BJWC2010]外星联络

    题目大意:给你一个长度为$n(n\leqslant3\times10^3)$的字符串,要你求出其中出现次数大于$1$的子串,并按字典序输出次数. 题解:建$SAM$后求出每个点的$size$,最后按字 ...

  8. BZOJ1977/LuoguP4180【模板】严格次小生成树[BJWC2010] (次小生成树)

    这道题本身思维难度不大,但综合性强,细节多 在其上浪一个早上,你的 最小生成树 树链剖分 线段树 DEBUG能力... 都大幅提升 细节与思路都在代码里面了. 欢迎hack. #include< ...

  9. 【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】

    P4180 [模板]严格次小生成树[BJWC2010] 题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说, ...

随机推荐

  1. Django2.0 path和re_path使用

    Django2.0发布后,很多人都拥抱变化,加入了2的行列.但是和1.11相比,2.0在url的使用方面发生了很大的变化,下面介绍一下: 一.实例 先看一个例子: from django.urls i ...

  2. 线程执行synchronized同步代码块时再次重入该锁过程中抛异常,是否会释放锁

    一个线程执行synchronized同步代码时,再次重入该锁过程中,如果抛出异常,会释放锁吗? 如果锁的计数器为1,抛出异常,会直接释放锁: 那如果锁的计数器为2,抛出异常,会直接释放锁吗? 来简单测 ...

  3. tomcat 修改jdk版本号

    set JAVA_OPTS=-Djute.maxbuffer=2048000 set console_log=true set CATALINA_OPTS=-server -Xdebug -Xnoag ...

  4. redis编译安装

    centos7 redis-4.0.6 make 报错 jemalloc.h: No such file or directory make MALLOC=libc MALLOC默认值是jemallo ...

  5. 安装三代组装canu、smartdenovo、wtdbg及矫正软件Racon、Nanopolish的安装

    1)三代组装软件 ------------------------------------------------------------------canu--------------------- ...

  6. 03_java基础(六)之CRUD实现

    1.简单实现 package com.day01.station.dao; /** * Created by Administrator on 2018/2/1. */ import java.sql ...

  7. love is ... ...

    16 years old, love is dream.20 years old, love is sex.30 years old, love is marriage. 40 years old, ...

  8. RelativeLayout 相对布局

    根据父容器来定位: 想位于哪,哪个属性就设置为true 左对齐:android:layout_alighParentLeft 右对齐:android:layout_alighParentRight 顶 ...

  9. 安卓操作系统版本(Version)与应用程序编程接口等级(Application Programming Interface Level)对照表

    Android是一种基于Linux的自由及开放源代码的操作系统,主要使用于移动设备,如智能手机和平板电脑. 使用Android API,可以在Java环境开发App,编译.打包后可在Android系统 ...

  10. 【Android端】代码打包成jar包/aar形式

    Android端代码打包成jar包和aar形式: 首先,jar包的形式和aar形式有什么区别? 1.打包之后生成的文件地址: *.jar:库/build/intermediates/bundles/d ...