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

在其上浪一个早上,你的

最小生成树 树链剖分 线段树 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. 前端获取cookie,并解析cookie成JSON对象

    getCookie() { let strcookie = document.cookie; //获取cookie字符串 let arrcookie = strcookie.split("; ...

  2. Java开发学习(一)----初识Spring及其核心概念

    一. Spring系统架构 1.1 系统架构图 Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基. Spring Framework的发展也经历了很多版本的变更,每 ...

  3. UVA471 Magic Numbers 题解

    1.题目 题意很简单:输入n,枚举所有的a,b,使得 (1)满足a/b=n. (2)满足a,b各个位上的数字不相同. 2.思路 (1)对于被除数,要满足各个位上的数字,显然最大枚举到987654321 ...

  4. Linux查看日志文件写入速度的4种方法

    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 有时,我们需要查看某个文件的增长速度,如日志文件,以此来感受系统的负载情况,因为一般情况下,日志写入越快,说明系统 ...

  5. Docker容器编译安装Nginx

    Docker容器编译安装Nginx,最简单的Nginx配置. 创建容器&进入容器 宿主机2080映射容器的80端口 [root@localhost ~]# docker run -i -d - ...

  6. XDEBUG 选项

    到官网 http://www.xdebug.com/download.php 下载 找到对应PHP版本的 Xdebug ,后面带 TS 的为线程安全,本机环境为 win7 64 + php-5.5.1 ...

  7. 【spring源码系列】之【FactoryBean类型的接口】

    1.概述 目前我们知道,spring创建bean有多种方式,比如xml方式创建,比如@Component,@Service,@Controler,@Repository注解创建,比如@Autowire ...

  8. kruskal 及其应用

    kruskal 最小生成树 kruskal 是一种常见且好理解的最小生成树(MST)算法. 前置知识 并查集和路径压缩 生成树 在有 n 的顶点的无向图中,取其中 n-1 条边相连,所得到的树即为生成 ...

  9. ansible管理windows主机

    1. 在windows开启winrm winrm service 默认都是未启用的状态,先查看状态:如无返回信息,则是没有启动: winrm enumerate winrm/config/listen ...

  10. python简单处理验证码,三分钟,不能再多了

    序言 大家好鸭, 又是我小熊猫啦 我们在做采集数据的时候,过快或者访问频繁,或者一访问就给弹出验证码,然后就蚌珠了~今天就给大家来一个简单处理验证码的方法 环境模块 Python和pycharm如果还 ...