「luogu2387」[NOI2014] 魔法森林
「luogu2387」[NOI2014] 魔法森林
题目大意
\(n\) 个点 \(m\) 条边的无向图,每条边上有两个权值 \(a,b\),求从 \(1\) 节点到 \(n\) 节点 \(max\{a\}+max\{b\}\) 的最小值。图中可能有重边和自环。\((n \leq 5 \times 10^4 , m \leq 10^5)\)
一句话题解
考虑生成树 ( 过程类似 \(kruskal\) );
把边按照 \(a\) 从小到大排序,\(1-m\) 枚举边,设边连接的两点为 \(u , v\);
若 \(u , v\) 已经在一个联通块中,则在 \(u\) 到 \(v\) 的路径中找一个 \(b\) 的最大值 \(b_{max}\),如果 \(b_{max} > b当前枚举到的边\),就把 \(当前枚举到的边\) 连接,\(max_b\) 所在的边断开;
若 \(u , v\) 不在一个联通块中,则直接连接;
边用 \(lct\) 维护即可;
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
inline int in() {
int x=0;char c=getchar();bool f=false;
while(c<'0'||c>'9') f|=c=='-', c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
return f?-x:x;
}
const int N = 5e4+5, M = 1e5+5;
struct edge {
int u, v, a, b;
friend inline bool operator < (const edge &x, const edge &y) {
return x.a < y.a;
}
}e[M];
int n, m;
template<typename T>inline void chk_min(T &_, T __) { _=_<__?_:__; }
struct link_cut_tree {
#define lson c[p][0]
#define rson c[p][1]
int c[N+M][2], fa[N+M], val[N+M], max[N+M];
bool rev[N+M];
inline bool nroot(int p) {
return c[fa[p]][0]==p||c[fa[p]][1]==p;
}
inline void push_up(int p) {
max[p]=p;
if(lson&&val[max[lson]]>val[max[p]]) max[p]=max[lson];
if(rson&&val[max[rson]]>val[max[p]]) max[p]=max[rson];
}
inline void rever(int p) {
std::swap(lson, rson);
rev[p]^=1;
}
inline void push_down(int p) {
if(rev[p]) {
if(lson) rever(lson);
if(rson) rever(rson);
rev[p]=false;
}
}
void push_all(int p) {
if(nroot(p)) push_all(fa[p]);
push_down(p);
}
inline void rotate(int x) {
int y=fa[x], z=fa[y], l=c[y][1]==x, r=l^1;
if(nroot(y)) c[z][c[z][1]==y]=x;
fa[x]=z, fa[c[x][r]]=y, fa[y]=x;
c[y][l]=c[x][r], c[x][r]=y;
push_up(y), push_up(x);
}
inline void splay(int x) {
int y, z;
push_all(x);
while(nroot(x)) {
y=fa[x], z=fa[y];
if(nroot(y)) rotate(c[y][0]==x^c[z][0]==y?x:y);
rotate(x);
}
}
inline void access(int p) { for(int s=0;p;p=fa[s=p]) splay(p), rson=s, push_up(p); }
inline void make_root(int p) { access(p), splay(p), rever(p); }
inline void split(int p, int s) { make_root(p), access(s), splay(s); }
inline void link(int p, int s) { make_root(p), fa[p]=s; }
inline void cut(int p, int s) { split(p, s), c[s][0]=fa[p]=0, push_up(s); }
inline int select(int p, int s) { split(p, s); return max[s]; }
#undef lson
#undef rson
}lct;
struct disjoint_set_union {
int fa[N];
int get_fa(int u) { return u==fa[u]?u:fa[u]=get_fa(fa[u]); }
inline int & operator [] (int u) { return fa[u]; }
}dsu;
inline int kruskal() {
int ret=-1;
std::sort(e+1, e+1+m);
for(int i=1;i<=n;++i) dsu[i]=i;
for(int i=n+1;i<=n+m;++i) lct.val[i]=e[i-n].b;
for(int i=1;i<=n+m;++i) lct.max[i]=i;
for(int i=1;i<=m;++i) {
if(e[i].u==e[i].v) continue;
int u=dsu.get_fa(e[i].u), v=dsu.get_fa(e[i].v);
if(u==v) {
int k=lct.select(e[i].u, e[i].v);
if(lct.val[k]>e[i].b) {
lct.cut(e[k-n].u, k), lct.cut(k, e[k-n].v);
lct.link(e[i].u, i+n), lct.link(i+n, e[i].v);
}
}
else {
dsu[u]=v;
lct.link(e[i].u, i+n), lct.link(i+n, e[i].v);
}
if(dsu.get_fa(1)==dsu.get_fa(n)) {
lct.split(1, n);
if(ret==-1) ret=lct.val[lct.max[n]]+e[i].a;
else chk_min(ret, lct.val[lct.max[n]]+e[i].a);
}
}
return ret;
}
int main() {
n=in(), m=in();
for(int i=1;i<=m;++i)
e[i]=(edge){in(), in(), in(), in()};
printf("%d\n", kruskal());
return 0;
}
「luogu2387」[NOI2014] 魔法森林的更多相关文章
- NOI2014 魔法森林
3669: [Noi2014]魔法森林 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 106 Solved: 62[Submit][Status] ...
- bzoj 3669: [Noi2014]魔法森林 动态树
3669: [Noi2014]魔法森林 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 363 Solved: 202[Submit][Status] ...
- BZOJ 3669: [Noi2014]魔法森林( LCT )
排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...
- bzoj 3669: [Noi2014]魔法森林
bzoj 3669: [Noi2014]魔法森林 Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号 ...
- 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 ...
- P2387 [NOI2014]魔法森林(LCT)
P2387 [NOI2014]魔法森林 LCT边权维护经典题 咋维护呢?边化为点,边权变点权. 本题中我们把边对关键字A进行排序,动态维护关键字B的最小生成树 加边后出现环咋办? splay维护最大边 ...
- [NOI2014]魔法森林 LCT
题面 [NOI2014]魔法森林 题解 一条路径的代价为路径上的\(max(a[i]) + max(b[i])\),因为一条边同时有$a[i], b[i]$2种权值,直接处理不好同时兼顾到,所以我们考 ...
- bzoj 3669: [Noi2014]魔法森林 -- 动点spfa
3669: [Noi2014]魔法森林 Time Limit: 30 Sec Memory Limit: 512 MB 动点spfa Description 为了得到书法大家的真传,小E同学下定决心 ...
随机推荐
- HTML HTML5 新特性
一.语义化标签 语义化标签 为页面提供了更好的页面结构. 描述 属性 <header></header> 定义文档的头部区域 <footer></foote ...
- C#,WPF中使用多文本显示数据,并对其数据进行关键字高亮等操作
需求:针对多文本信息显示,我们需要对其内容中的某些关键字或者某行进行高亮显示,并用不同颜色显示. 分析:在C#中,首先要进行多文本信息显示,可以RichTextBox(不要使用TextBox)控件,该 ...
- Python_if
if if c语言中的if语句格式如下: if (条件) { 结果} python的格式与其不同,定义了自己的格式,更加的简明: if 条件 : 结果 print(111) if 3 > 2: ...
- 【问题解决方案】Github中的jupyter notebook文件(.ipynb)加载失败/失败
两个方法: 法一:本机安装jupyter notebook的情况下直接下载文件并打开 本机打开的话会在浏览器中显示,地址为localhost:8888,也就是本机 法二:在线打开:利用 'https: ...
- CH1201 最大子序和
http://contest-hunter.org:83/contest/0x10%E3%80%8C%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9 ...
- Go语言中Loop的注意点
Go语言和其他语言不一样,它只有一种循环方式,就是for语句 可以参考如下公式: for initialisation; condition; post{ //Do Something } 执行顺序 ...
- [CF 666E] Forensic Examination
Description 传送门 Solution 对 \(T[1..m]\) 建立广义后缀自动机,离线,找出代表 \(S[pl,pr]\) 的每个节点,线段树合并. Code #include < ...
- BZOJ2406矩阵——有上下界的可行流+二分答案
题目描述 输入 第一行两个数n.m,表示矩阵的大小. 接下来n行,每行m列,描述矩阵A. 最后一行两个数L,R. 输出 第一行,输出最小的答案: 样例输入 2 2 0 1 2 1 0 1 样例输出 1 ...
- BlockQueue 解析
生产者.消费者模式 https://www.jianshu.com/p/024a36b83099
- MySQ数据备份
MySQL备份概述 问题:备份和冗余有什么区别? 备份:能够防止由于机械故障以及人为操作带来的数据丢失,例如将数据库文件保存在了其它地方. 冗余:数据有多份冗余,但不等于备份,只能防止机械故障带来的数 ...