[NOI2014] 魔法森林

Description

给定一张图,每条边 \(i\) 的权为 \((a_i,b_i)\), 求一条 \(1 \sim n\) 路径,最小化 \(\max_{i\in P}{a_i} + \max_{i\in P}{b_i}\)

Solution

如果我们限定最大的 \(b_i\) ,那么路径一定在以 \(a_i\) 为权的最小生成树上。

Proof. 考虑反证,假设这条路径中有一条边不在 MST 上,那么这条非树边与树必然形成一个环,很显然用这条边换掉环上任意一条其它边会减小生成树的权值,与最小生成树的条件矛盾。

利用这个性质构造算法。我们从小到大枚举 \(b_i\) 的最大值,依次将边加入树中,同时用 LCT 维护以 \(a_i\) 为边权的最小生成树即可。

维护最小生成树的方法非常简单。利用 LCT 维护树链最大值,当新边 \((u,v,w)\) 加入时,我们考虑如果这条边比树链 \(u \sim v\) 上的最大值小,那么就用它换掉那个最大值的边。因此 LCT 上需要维护最大值以及最大值的位置。

使用 LCT 维护边权通常的做法是对边建点,点权赋为边权,而真实的点则不具有点权。同时维护边的基本信息。

以下阐述为较为具体的实现方式

在本题中,我们可以用编号 \(1 \sim n\) 的点来代表真实点,用编号 \(n+1 \sim n+m\) 的点来代表边,同时在一个结构体数组中以 \((u,v,w)\) 的形式记录边权的基本信息。注意边的编号可以用按照 \(b_i\) 为关键字排序后的代替。

在 LCT 的实现层面上,我们可以姑且忽略这一切,全当作维护树链的最大点权和最大点权点编号。

当我们需要查询 \(u \sim v\) 间的最大边权时,我们只需要在 LCT 上询问即可。

当我们需要删除一条边的时候,我们只需要知道它的编号 \(i\) ,然后断开 \((u_i, n+i)\) 和 \((v_i, n+i)\)

当我们需要加入一条边的时候,我们只需要知道它的编号 \(i\) ,然后连接 \((u_i, n+i)\) 和 \((v_i, n+i)\)

Code
#include <bits/stdc++.h>
using namespace std; #define int long long const int N = 1000000; int n,m; struct Edge {
int u,v,w,b;
bool operator < (const Edge &x) const {
return b < x.b;
}
} e[N]; struct LinkCutTree {
int top, q[N], ch[N][2], fa[N], rev[N], mx[N], mp[N], val[N];
inline void pushup(int x) {
mx[0]=mp[0]=0;
mx[x] = max(max(mx[ch[x][0]],mx[ch[x][1]]),val[x]);
if(mx[x] == mx[ch[x][0]])
mp[x]=mp[ch[x][0]];
if(mx[x] == mx[ch[x][1]])
mp[x]=mp[ch[x][1]];
if(mx[x] == val[x])
mp[x]=x;
}
inline void pushdown(int x) {
if(!rev[x])
return;
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
rev[x]^=1;
swap(ch[x][0],ch[x][1]);
}
inline bool isroot(int x) {
return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x;
}
inline void rotate(int p) {
int q=fa[p], y=fa[q], x=ch[fa[p]][1]==p;
ch[q][x]=ch[p][x^1];
fa[ch[q][x]]=q;
ch[p][x^1]=q;
fa[q]=p;
fa[p]=y;
if(y)
if(ch[y][0]==q)
ch[y][0]=p;
else if(ch[y][1]==q)
ch[y][1]=p;
pushup(q);
pushup(p);
}
inline void splay(int x) {
q[top=1]=x;
for(int i=x; !isroot(i); i=fa[i])
q[++top]=fa[i];
for(int i=top; i; i--)
pushdown(q[i]);
for(; !isroot(x); rotate(x))
if(!isroot(fa[x]))
rotate((ch[fa[x]][0]==x)==(ch[fa[fa[x]]][0]==fa[x])?fa[x]:x);
}
void access(int x) {
for(int t=0; x; t=x,x=fa[x])
splay(x),ch[x][1]=t,pushup(x);
}
void makeroot(int x) {
access(x);
splay(x);
rev[x]^=1;
}
int find(int x) {
access(x);
splay(x);
while(ch[x][0])
x=ch[x][0];
return x;
}
void split(int x,int y) {
makeroot(x);
access(y);
splay(y);
}
void cut(int x,int y) {
split(x,y);
if(ch[y][0]==x)
ch[y][0]=0, fa[x]=0;
}
void link(int x,int y) {
makeroot(x);
fa[x]=y;
}
void setval(int p,int v) {
val[p]=mx[p]=v;
mp[p]=p;
}
int queryv(int p,int q) {
split(p,q);
return mx[q];
}
int queryp(int p,int q) {
split(p,q);
return mp[q];
}
} lct; bool check(int p,int q) {
return lct.find(p)==lct.find(q);
} int queryv(int p,int q) {
return lct.queryv(p,q);
} int queryp(int p,int q) {
return lct.queryp(p,q)-n;
} void link(int i) {
lct.link(n+i,e[i].u);
lct.link(n+i,e[i].v);
} void cut(int i) {
lct.cut(n+i,e[i].u);
lct.cut(n+i,e[i].v);
} int ans = 1e+12; signed main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++) {
scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].w,&e[i].b);
}
sort(e+1,e+m+1);
for(int i=1;i<=n;i++) lct.setval(i, 0);
for(int i=1;i<=m;i++) lct.setval(i+n, e[i].w);
for(int i=1;i<=m;i++) {
if(check(e[i].u,e[i].v)) {
int v=queryv(e[i].u,e[i].v), p=queryp(e[i].u,e[i].v);
if(v > e[i].w) {
cut(p);
link(i);
}
}
else {
link(i);
}
if(check(1,n)) {
ans = min(ans, queryv(1,n) + e[i].b);
} }
if(ans < (int)1e+12) cout<<ans<<endl;
else cout<<-1<<endl;
}

[NOI2014] 魔法森林 - Link Cut Tree的更多相关文章

  1. BZOJ 3669 [Noi2014]魔法森林 ——SPFA / Link-Cut Tree

    [题目分析] 大意就是有一张图,边权有两个值,ai和bi 找到一条路径,使得路径上的max(ai)+max(bi)最小. 遇到有两个权值或者多个权值的时候,如果他们互相影响,试着用分块搞一搞. 如果互 ...

  2. 【BZOJ3669】【Noi2014】魔法森林(Link-Cut Tree)

    [BZOJ3669][Noi2014]魔法森林(Link-Cut Tree) 题面 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n ...

  3. link cut tree 入门

    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...

  4. Link Cut Tree 总结

    Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...

  5. 学习笔记:Link Cut Tree

    模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...

  6. BZOJ_3669_[Noi2014]魔法森林_LCT

    BZOJ_3669_[Noi2014]魔法森林_LCT Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节 ...

  7. bzoj 3669: [Noi2014]魔法森林 (LCT)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec  ...

  8. 「luogu2387」[NOI2014] 魔法森林

    「luogu2387」[NOI2014] 魔法森林 题目大意 \(n\) 个点 \(m\) 条边的无向图,每条边上有两个权值 \(a,b\),求从 \(1\) 节点到 \(n\) 节点 \(max\{ ...

  9. P2387 [NOI2014]魔法森林(LCT)

    P2387 [NOI2014]魔法森林 LCT边权维护经典题 咋维护呢?边化为点,边权变点权. 本题中我们把边对关键字A进行排序,动态维护关键字B的最小生成树 加边后出现环咋办? splay维护最大边 ...

随机推荐

  1. Maven国内镜像配置(阿里云)-sunziren

    <?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...

  2. tcp客户端从服务器下载文本文件

    代码讲解: server import socket def send_file_client(new_client_socket, new_client_addr): # 接收客户端需要下载的文件名 ...

  3. 吴裕雄--天生自然HADOOP操作实验学习笔记:hive安装

    实验目的 了解hive的原理和安装方式 学习使用MySQL数据库 使用hive进行基本操作 实验原理 1.Hive Hive是一个数据仓库技术,包括解释器.编译器.优化器,一次将一个sql语句装化为m ...

  4. python学习随笔2:python判断和循环

    1.if-else _username = 'heyue' _password = ' username = input("username:") password = input ...

  5. ASP.NET MVC自定义Numberic属性的验证信息

    最近在使用MVC4时碰到一个Model验证的问题:整型属性输入非整型字符串时,错误信息总是“字段 XXX 必须是一个数字”,我总觉得这句话读起来很别扭,所以就萌生了要改变这个默认错误提示信息的念头,但 ...

  6. ECMAScript基本对象——Date日期对象

    1.创建 var 对象名 = new Date(); 2.方法 ①toLocaleString()据本地时间格式,把 Date 对象转换为字符串.和电脑的语言位置有关 ②getTime()返回 197 ...

  7. sublime—text终端无法输入,不支持scanf、input等语法问题的解决

    sublimetext是个很好用的轻量编辑器,,支持多语言语法高亮,自动补全,快捷键编译运行,而且ui也不错挺简洁,我一直在用.我之前浏览帖子时候看到有些人也在用这个编辑器. 但是吧,这个编辑器的的编 ...

  8. Java中异步注解@Async的陷阱

    或许,你在Java后端添加异步过程时会这样处理,然后摇摇大摆.灰溜溜地闪,而实际的运行结果却并不是我们期望的那样.那么,现在就将试验结果记录如下,以便少走弯路. (一)在Controller层的公开接 ...

  9. 正则表达式[\w]+,\w+,[\w+]

    正则表达式[\w]+,\w+,[\w+] 三者区别? [],[ABC]+,[\w./-]+ 表达什么? 正则表达式[\w]+,\w+,[\w+] 三者有何区别:[\w]+和\w+没有区别,都是匹配数字 ...

  10. net core+Redis+IIS+nginx实现Session共享

    .Net Core Web Api实践(二).net core+Redis+IIS+nginx实现Session共享   前言:虽说公司app后端使用的是.net core+Redis+docker+ ...