这道题本身思维难度不大,但综合性强,细节多

在其上浪一个早上,你的

最小生成树 树链剖分 线段树 DEBUG能力...

都大幅提升

细节与思路都在代码里面了。

欢迎hack.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define R(a,b,c) for(register int a = (b); a <= (c); ++a)
#define nR(a,b,c) for(register int a = (b); a >= (c); --a)
#define Max(a,b) ((a) > (b) ? (a) : (b))
#define Min(a,b) ((a) < (b) ? (a) : (b))
#define ll long long
#define Fill(a,b) memset(a, b, sizeof(a)) //#define ON_DUBUG #ifdef ON_DUBUG #define D_e_Line printf("\n\n-------------------\n\n") #else #define D_e_Line ; #endif struct ios{
template<typename ATP>ios& operator >> (ATP &x){
x = 0; int f = 1; char c;
for(c = getchar(); c < '0' || c > '9'; c=getchar()) if(c == '-') f = -1;
while(c >= '0' && c <='9') x = x * 10 + (c ^ '0'), c = getchar();
x *= f;
return *this;
}
}io; using namespace std; //#define TEST_INPUT
#ifdef TEST_INPUT
int main(){
while(1){
ll x;
io >> x;
cout << x << endl;
}
}
#endif const int N = 100007;
const int M = 300007; int n, m; struct Node{
int x,y,w,tag;
bool operator < (const Node &b)const{
return w < b.w;
}
}a[M];
struct Edge{
int nxt,pre;
long long w;
}e[M<<1];
int head[N],cntEdge;
inline void add(int u,int v,long long w){
e[++cntEdge] = (Edge){head[u], v, w}, head[u] = cntEdge;
} long long MST;
int f[N];
inline int Find(int x){
return x == f[x] ? x : f[x] = Find(f[x]);
}
inline void Kruskal(){
R(i,1,n) f[i] = i;//Always remember, Fool orphan! Get your father at the first time!
sort(a + 1, a + m + 1);
int tot = 1;
R(i,1,m){
int p = Find(a[i].x), q =Find(a[i].y);
if(p != q){
f[p] = q;
MST += a[i].w;
a[i].tag = true;
if(++tot >= n)
return;
}
} } int wSon[N];
int fa[N],son[N],siz[N],dep[N];
inline void DFS_First(int u,int father){
dep[u] = dep[father] + 1, siz[u] = 1, fa [u] = father;
for(register int i = head[u]; i; i = e[i].nxt){
int v = e[i].pre;
if(v == father) continue;
DFS_First(v, u);
siz[u] += siz[v];
if(!son[u] || siz[v] > siz[son[u]]){
son[u] = v;
//Treat value(edge) as value(node)
wSon[u] = e[i].w;
}
}
}
int top[N],rnk[N],dfn[N],dfnIndex;
inline void DFS_Second(int u,int ancester,int w){
top[u] = ancester, dfn[u] = ++dfnIndex, rnk[dfnIndex] = w;
if(!son[u]) return;
DFS_Second(son[u], ancester, wSon[u]);//e[i].w or wSon[u] ? // The answer is wSon[u] because it's the weight of this node
for(register int i = head[u]; i; i = e[i].nxt){
int v = e[i].pre;
if(v != fa[u] && v != son[u])
DFS_Second(v, v, e[i].w);//e[i].w or wSon[u] ? // The answer is e[i].w because it's the cost to the next node.
}
} #define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
struct SegmentTree{
int mx,sc;
}t[M<<2];
inline void Pushup(int rt){
t[rt].mx = Max(t[rt<<1].mx, t[rt<<1|1].mx);
t[rt].sc = Max(t[rt].mx != t[rt<<1].mx ? t[rt<<1].mx : t[rt<<1].sc, t[rt].mx != t[rt<<1|1].mx ? t[rt<<1|1].mx : t[rt<<1|1].sc);
}
inline void Build(int rt,int l,int r){
if(l == r){
t[rt].mx = rnk[l];
t[rt].sc = -1;
//Pushup(rt);//Do there really need pushup? // No! You do not have to pull a tree you just put into the groud.
return;
}
int mid = l + r >> 1;
Build(lson), Build(rson);
Pushup(rt);
}
SegmentTree Query(int rt,int l,int r,int L,int R){
if(L <= l && r <= R) return t[rt]; SegmentTree tmp_1, tmp_2, res;
tmp_1.mx = tmp_1.sc = tmp_2.mx = tmp_2.sc;//Need initial? And why?
/*
There is a strange problem
if I don't initial, the program will give a wrong answer.
But if I write:
tmp_1.mx = tmp_1.sc = tmp_2.mx = tmp_2.sc
It'll be right.
Pay attention, I do not write:
tmp_1.mx = tmp_1.sc = tmp_2.mx = tmp_2.sc = 0 So what happend to this initial sentence?
I believe you can find out by yourself.
*/ int mid = l + r >> 1;
//D_e_Line;
if(L <= mid) tmp_1 = Query(lson, L, R);
if(mid < R) tmp_2 = Query(rson, L, R); res.mx = Max(tmp_1.mx, tmp_2.mx);
res.sc = Max(res.mx != tmp_1.mx ? tmp_1.mx : tmp_1.sc, res.mx != tmp_2.mx ? tmp_2.mx : tmp_2.sc); return res;
} inline long long QueryPath(int u,int v,long long w){
long long sum = 0;
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]]) u^=v^=u^=v;
SegmentTree tmp = Query(1, 1, n, dfn[top[u]], dfn[u]);
sum = Max(sum, tmp.mx != w ? tmp.mx : tmp.sc);
u = fa[top[u]];
}
if(u == v) return sum;//Is this so important? Is it the criminal of the endless of my program?//Well, for the second question, it may not. //And if I ignore it, it doesn't matter, but as it can make my program runs faster, why not?
if(dep[u] < dep[v]) u^=v^=u^=v;
SegmentTree tmp = Query(1, 1, n, dfn[v]+1, dfn[u]);//I'm not sure when I need use 'dfn[v]+1'
sum = Max(sum, tmp.mx != w ? tmp.mx : tmp.sc);
return sum;
} int main(){
io >> n >> m;
R(i,1,m){
int u,v,w;
io >> u >> v >> w;
a[i] = (Node){u, v, w, 0};
} Kruskal(); R(i,1,m){//Here ought to be m, not n! It's going through all the edges
if(a[i].tag == true){
add(a[i].x, a[i].y, a[i].w);
add(a[i].y, a[i].x, a[i].w);
}
} DFS_First(1, 0);
DFS_Second(1, 0, 0); Build(1, 1, n); int sum = 2147483647;
R(i,1,m){
if(a[i].tag == false){
sum = Min(sum, a[i].w - QueryPath(a[i].x, a[i].y, a[i].w));
}
} printf("%lld\n", MST + sum); return 0; }

BZOJ1977/LuoguP4180【模板】严格次小生成树[BJWC2010] (次小生成树)的更多相关文章

  1. 「LuoguP4180」 【模板】严格次小生成树[BJWC2010](倍增 LCA Kruscal

    题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...

  2. P4180 【模板】严格次小生成树[BJWC2010]

    P4180 [模板]严格次小生成树[BJWC2010] 倍增(LCA)+最小生成树 施工队挖断学校光缆导致断网1天(大雾) 考虑直接枚举不在最小生成树上的边.但是边权可能与最小生成树上的边相等,这样删 ...

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

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

  4. Luogu P4180 【模板】严格次小生成树[BJWC2010]

    P4180 [模板]严格次小生成树[BJWC2010] 题意 题目描述 小\(C\)最近学了很多最小生成树的算法,\(Prim\)算法.\(Kurskal\)算法.消圈算法等等.正当小\(C\)洋洋得 ...

  5. 洛谷 P4180 【模板】严格次小生成树[BJWC2010]【次小生成树】

    严格次小生成树模板 算法流程: 先用克鲁斯卡尔求最小生成树,然后给这个最小生成树树剖一下,维护边权转点权,维护最大值和严格次大值. 然后枚举没有被选入最小生成树的边,在最小生成树上查一下这条边的两端点 ...

  6. 【【模板】严格次小生成树[BJWC2010]】

    树上的路径怎么能没有树剖 显然,次小生成树和最小生成树只在一条边上有差距,于是我们就可以枚举这一条边,将所有边加入最小生成树,之后再来从这些并不是那么小的生成树中找到那个最小的 我们往最小生成树里加入 ...

  7. 【luogu P4180 严格次小生成树[BJWC2010]】 模板

    题目链接:https://www.luogu.org/problemnew/show/P4180 这个题卡树剖.记得开O2. 这个题inf要到1e18. 定理:次小生成树和最小生成树差距只有在一条边上 ...

  8. 【洛谷 P4180】【模板】严格次小生成树[BJWC2010](倍增)

    题目链接 题意如题. 这题作为我们KS图论的T4,我直接打了个很暴力的暴力,骗了20分.. 当然,我们KS里的数据范围远不及这题. 这题我debug了整整一个晚上还没debug出来,第二天早上眼前一亮 ...

  9. 洛谷P4180 【模板】严格次小生成树[BJWC2010] 题解

    虽然中途写的时候有点波折,但是最后一发A,还是有点爽. 这虽然是个模板题,但还是涉及到许多知识的= = 首先我们求出一个最小生成树,并且求出其边权和\(ans\).那么现在考虑加入其它的边,每次加入在 ...

随机推荐

  1. Hadoop入门学习笔记(二)

    Yarn学习 YARN简介 YARN是一个通用资源管理系统和调度平台,可为上层应用提供统一的资源管理和调度 YARN功能说明 资源管理系统:集群的硬件资源,和程序运行相关,比如内存.CPU等. 调度平 ...

  2. 博弈论(nim游戏,SG函数)

    说到自己,就是个笑话.思考问题从不清晰,sg函数的问题证明方法就在眼前可却要弃掉.不过自己理解的也并不透彻,做题也不太行.耳边时不时会想起alf的:"行不行!" 基本的小概念 这里 ...

  3. 深度学习与CV教程(6) | 神经网络训练技巧 (上)

    作者:韩信子@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/37 本文地址:http://www.showmeai.tech/article-det ...

  4. DS18B20数字温度计 (一) 电气特性, 供电和接线方式

    目录 DS18B20数字温度计 (一) 电气特性, 供电和接线方式 DS18B20数字温度计 (二) 测温, ROM和CRC校验 DS18B20数字温度计 (三) 1-WIRE总线ROM搜索算法 DS ...

  5. 关于 GIN 的路由树

    GIN 是一个 golang 常用的 Web 框架,它对 API 比较友好,源码注释也很明确明确,使用起来快速灵活,还有极高的容错率.标题中的路由我们可以简单理解为在浏览器中输入的页面地址,而&quo ...

  6. 『忘了再学』Shell流程控制 — 38、while循环和until循环介绍

    目录 1.while循环 2.until循环 1.while循环 对while循环来讲,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止.和for循环的第二种格式for((初始 ...

  7. SAP 动态选择屏幕实例

    DATA:BEGIN OF gs_sel, werks TYPE marc-werks, "工厂 matnr TYPE mara-matnr, "物料 mtart TYPE mar ...

  8. 多校联训 DP 专题

    [UR #20]跳蚤电话 将加边变为加点,方案数为 \((n-1)!\) 除以一个数,\(dp\) 每种方案要除的数之和即可. 点击查看代码 #include<bits/stdc++.h> ...

  9. PMP 考试常见工具与技术点总结

    转载请注明出处: 网络图:项目进度活动之间的逻辑关系,用来推算关键路径,最大浮动时间等: 横道图(甘特图):以图示的方式,通过活动列表和时间刻度,来展示项目获得那个顺序和持续时间 责任分配矩阵:每件事 ...

  10. C语言动态输出等腰三角形

    C语言动态输出等腰三角形 题目要求:输入行数 打印出对应行数的等腰三角形,要求使用for循环嵌套. 思路 while语句写外层死循环 用于判断输出的数据: 分析: 最外层for,来控制最外层行数,存储 ...