[NOI2014] 魔法森林 - Link Cut Tree
[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的更多相关文章
- BZOJ 3669 [Noi2014]魔法森林 ——SPFA / Link-Cut Tree
[题目分析] 大意就是有一张图,边权有两个值,ai和bi 找到一条路径,使得路径上的max(ai)+max(bi)最小. 遇到有两个权值或者多个权值的时候,如果他们互相影响,试着用分块搞一搞. 如果互 ...
- 【BZOJ3669】【Noi2014】魔法森林(Link-Cut Tree)
[BZOJ3669][Noi2014]魔法森林(Link-Cut Tree) 题面 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n ...
- link cut tree 入门
鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...
- Link Cut Tree 总结
Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...
- 学习笔记:Link Cut Tree
模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...
- BZOJ_3669_[Noi2014]魔法森林_LCT
BZOJ_3669_[Noi2014]魔法森林_LCT Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节 ...
- bzoj 3669: [Noi2014]魔法森林 (LCT)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec ...
- 「luogu2387」[NOI2014] 魔法森林
「luogu2387」[NOI2014] 魔法森林 题目大意 \(n\) 个点 \(m\) 条边的无向图,每条边上有两个权值 \(a,b\),求从 \(1\) 节点到 \(n\) 节点 \(max\{ ...
- P2387 [NOI2014]魔法森林(LCT)
P2387 [NOI2014]魔法森林 LCT边权维护经典题 咋维护呢?边化为点,边权变点权. 本题中我们把边对关键字A进行排序,动态维护关键字B的最小生成树 加边后出现环咋办? splay维护最大边 ...
随机推荐
- C# monitor keyboard and print pressed key
using System; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Diagnos ...
- docker - 如何清理硬盘中无关占用
背景 在使用docker进行容器化管理后会发现本次硬盘文件占用量在不断上升,并且即使是删除掉容器或者镜像也并不能释放掉对应的硬盘空间.本文将提供对应的docker命令用于真正释放掉该部分应被删除释放的 ...
- 论文阅读笔记(二十)【AAAI2019】:Spatial and Temporal Mutual Promotion for Video-Based Person Re-Identification
Introduction (1)Motivation: 作者考虑到空间上的噪声可以通过时间信息进行弥补,其原因为:不同帧的相同区域可能是相似信息,当一帧的某个区域存在噪声或者缺失,可以用其它帧的相同区 ...
- Deepin Linux下安装安卓应用的各种方式
没事啥折腾 Deepin Linux 的应用商店里集成了挺多安卓应用 , 没有的就只能自己想办法了. 我主要使用这几个app , 飞书,邮箱大师,还有一些公司内部app. 网上 搜索了一下 ,有以下几 ...
- 剑指offer-面试题12-矩阵中的路径-回溯法
/* 题目: 设计一个函数,判断一个矩阵中是否存在一条包含该字符串所有字符的路径. 路径可从字符串的任意一格开始,每一步可向上.下.左.右移动一格. 如果一条路径经过了矩阵中的某一格,那么该路径不能再 ...
- maven依赖包无法更新下载
在IDEA工程中导入已存在的module时,按默认设置,直到完成导入,结果所有的外部依赖包都无法更新下载,即使是更新了setting.xml配置文件信息,依旧是不能更新下载依赖包,现将具体的操作过程和 ...
- 2020牛客寒假算法基础集训营4-F树上博弈
链接:https://ac.nowcoder.com/acm/contest/3005/F来源:牛客网 题目描述 现有一个 n 个点,n-1条边组成的树,其中 1 号点为根节点. 牛牛和牛妹在树上玩游 ...
- 在Windows启动pyspark shell:Failed to find Spark jars directory. You need to build Spark before running this program
D:\Develop tools\spark-2.2.0-bin-hadoop2.7\bin>pyspark2.cmd 'tools\spark-2.2.0-bin-hadoop2.7\bin\ ...
- 微信公众号和小程序可以共用access_token值吗?
微信公众号和小程序可以共用access_token值吗? 答案:是不能的 因为两者都可通过统一接口(https://api.weixin.qq.com/cgi-bin/message/subscrib ...
- 题解 AT4278 【[ABC115A] Christmas Eve Eve Eve】
题目传送门. 分析 根据题目,我们可以发现要求如下: \(d\)的值 输出 \(d=25\) Christmas \(d=24\) Christmas Eve \(d=23\) Christmas E ...