[Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)
题面
传送门:https://www.luogu.org/problemnew/show/P2387
Solution
这题的思想挺好的。
对于这种最大值最小类的问题,很自然的可以想到二分答案。很不幸的是,这题是双关键字排序的,我们怎么二分呢?
先二分a再二分b?怎么看都布星啊。
那a+b作为关键字二分?也布星啊。
那咋搞啊?
不如,我们换个想法,我们把其中一个关键字枚举,再看在这个关键字的限制下,另外一个尽可能小。
仔细想想,应该是能覆盖到所有的情况的。
所以说,我们可考虑这样做:我们先枚举a的大小(即所选的边的a必须小于这个值),在满足前者的条件下,使得从出发先到终点的路上的最大的b尽可能小。
对于第二个问题,是不是很眼熟?没错,这个问题就是著名的原题货车运输:我们要使得路径上经过的b值的最大值最小,这条路径一定是在以b为关键字的最小生成树上的(具体证明请移步货车运输那道题的题解)。
所以说,我们现在研究的问题就变为了如何快速的维护一个变化的最小生成树。
快速维护变化的树,我们可以很自然地想到使用LCT来维护。再结合我们之前维护动态最小生存树的知识:每加入一条边,它必定会连接两个点而形成一个环,我们要判断这条边是否会在新的生成树上,只需要看一下环上的最大的边权和这条边的关系就好了,如果这条边的边权比环上的最大值还要小,我们就可以把环上的那条最大的边断开,接上我们这条新的边。否则的话,这条边一定不会成为新的最小生成树的一部分。
所以说,我们的LCT只需要在每新加入一条边时,检查其连接的两端是否是联通的。如果不联通的话,加入这条边一定是没有问题的。如果联通的话,就把所连两端的链split出来,找到最大值,比较一下大小关系就好。
至于如何用LCT维护边,我的方法是用点来代替边,即一条边以一个有连向它的两个端点的边的点来替代。具体写法可以参照一下代码。
时间复杂度为$O(n*logn*logn)$
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long read()
{
long long x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
const int M=100000+100;
const int N=50000+100;
const int T=N+M;
struct road
{
int s,t,a,b;
}e[M];
int n,m;
bool cmp(road x,road y)
{
return x.a<y.a;
}
struct LCT
{
int son[T][2],fa[T],lazy[T],MAX[T],num[T],mstack[T],top;
inline void Update(int x)
{
MAX[x]=0;
if(num[MAX[son[x][0]]]>=num[x] and num[MAX[son[x][0]]]>=num[MAX[son[x][1]]])
MAX[x]=MAX[son[x][0]];
if(num[MAX[son[x][1]]]>=num[x] and num[MAX[son[x][1]]]>=num[MAX[son[x][0]]])
MAX[x]=MAX[son[x][1]];
if(num[x]>=num[MAX[son[x][0]]] and num[x]>=num[MAX[son[x][1]]])
MAX[x]=x;
}
inline void Mirror(int x)
{
lazy[x]=!lazy[x],swap(son[x][0],son[x][1]);
}
inline void PushDown(int x)
{
if(lazy[x]==0) return;
lazy[x]=0;
Mirror(son[x][0]),Mirror(son[x][1]);
}
inline bool IsRoot(int x)
{
return x!=son[fa[x]][0] and x!=son[fa[x]][1];
}
inline void Rotate(int x,int type)
{
int y=fa[x],z=fa[y];
if(IsRoot(y)==false) son[z][y==son[z][1]]=x;
fa[x]=z;
son[y][!type]=son[x][type],fa[son[x][type]]=y;
son[x][type]=y,fa[y]=x;
Update(y),Update(x);
}
inline void Splay(int x)
{
mstack[top=1]=x;
for(int i=x;i!=0;i=fa[i])
mstack[++top]=fa[i];
for(int i=top;i>=1;i--)
PushDown(mstack[i]);
while(IsRoot(x)==false)
{
if(x==son[fa[x]][fa[x]==son[fa[fa[x]]][1]] and IsRoot(fa[x])==false)
Rotate(fa[x],x==son[fa[x]][0]),
Rotate(x,x==son[fa[x]][0]);
else
Rotate(x,x==son[fa[x]][0]);
}
}
void Access(int x)
{
for(int t=0;x!=0;t=x,x=fa[x])
Splay(x),son[x][1]=t,fa[t]=x,Update(x);
}
inline void MakeRoot(int x)
{
Access(x),Splay(x);
Mirror(x);
}
inline int FindRoot(int x)
{
Access(x),Splay(x);
while(son[x][0]!=0)
PushDown(x),x=son[x][0];
Splay(x);
return x;
}
inline void Link(int x,int y)//x->y
{
if(FindRoot(x)==FindRoot(y)) return;
MakeRoot(x);
fa[x]=y;
}
inline void Split(int x,int y)//root:y
{
MakeRoot(x);
Access(y),Splay(y);
}
inline void Cut(int x,int y)
{
Split(x,y);
if(x==son[y][0] and fa[x]==y)
{
son[y][0]=fa[x]=0;
Update(y);
}
}
inline int Query(int x,int y)
{
MakeRoot(x);
Access(y),Splay(y);
return MAX[y];
}
inline void AddLine(int x)
{
if(e[x].s==e[x].t) return;//自环
num[n+x]=e[x].b,MAX[n+x]=n+x;
if(FindRoot(e[x].s)!=FindRoot(e[x].t))
{
Link(n+x,e[x].s),Link(n+x,e[x].t);
return ;
}
int t=Query(e[x].s,e[x].t);
if(num[n+x]<num[t])
{
Cut(e[t-n].s,t);
Cut(e[t-n].t,t);
Link(e[x].s,n+x);
Link(e[x].t,n+x);
}
}
inline int Query2()
{
if(FindRoot(n)!=FindRoot(1)) return 0x3f3f3f3f;
return num[Query(1,n)];
}
}lct;
int main()
{
n=read(),m=read();
for(int i=1;i<=m;i++)
e[i].s=read(),e[i].t=read(),e[i].a=read(),e[i].b=read(); sort(e+1,e+1+m,cmp);
int ans=0x3f3f3f3f;
for(int i=1;i<=m;i++)
{
lct.AddLine(i);
ans=min(ans,e[i].a+lct.Query2());
} if(ans==0x3f3f3f3f)
printf("-1");
else
printf("%d",ans);
return 0;
}
[Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)的更多相关文章
- P2387 [NOI2014]魔法森林 LCT维护最小生成树
\(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...
- 洛谷P2387 [NOI2014]魔法森林(LCT)
魔法森林 题目传送门 解题思路 把每条路按照\(a\)的值从小到大排序.然后用LCT按照b的值维护最小生成树,将边按照顺序放入.如果\(1\)到\(n\)有了一条路径,就更新最小答案.这个过程就相当于 ...
- luogu P2387 [NOI2014]魔法森林
传送门 这题似乎不好直接做,可以考虑按照\(a_i\)升序排序,然后依次加边更新答案 具体实现方法是用lct维护当前的树,这里需要维护链上最大的\(b_i\).每次加一条边,如果加完以后没有环直接加, ...
- Vijos1865 NOI2014 魔法森林 LCT维护生成树
基本思路: 首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值 如果加边过程中生成了环,则删除环中weightB最大的边 由于是无向图,点之间没有拓扑序, ...
- 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树
这道题看题意是在求一个二维最小瓶颈路,唯一可行方案就是枚举一维在这一维满足的条件下使另一维最小,那么我们就把第一维排序利用A小的边在A大的情况下仍成立来动态加边维护最小生成树. #include &l ...
- P2387 [NOI2014]魔法森林(LCT)
P2387 [NOI2014]魔法森林 LCT边权维护经典题 咋维护呢?边化为点,边权变点权. 本题中我们把边对关键字A进行排序,动态维护关键字B的最小生成树 加边后出现环咋办? splay维护最大边 ...
- 洛谷 P2387 [NOI2014]魔法森林 解题报告
P2387 [NOI2014]魔法森林 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2 ...
- BZOJ 3669: [Noi2014]魔法森林( LCT )
排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...
- bzoj 3669: [Noi2014]魔法森林 (LCT)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3669 题面: 3669: [Noi2014]魔法森林 Time Limit: 30 Sec ...
随机推荐
- centos7修改ssh端口及添加ssh监听端口
ssh 修改默认端口 [root@node-1 ~]# vi /etc/ssh/sshd_config 修改port 为 5522 重启[root@node-1 ~]# systemctl resta ...
- Trie树【字典树】浅谈
最近随洛谷日报看了一下Trie树,来写一篇学习笔记. Trie树:支持字符串前缀查询等(目前我就学了这些qwq) 一般题型就是给定一个模式串,几个文本串,询问能够匹配前缀的文本串数量. 首先,来定义下 ...
- 让我们创建屏幕- Android UI布局和控件
下载LifeCycleTest.zip - 278.9 KB 下载ViewAndLayoutLessons_-_Base.zip - 1.2 MB 下载ViewAndLayoutLessons_-_C ...
- 解决mvn clean install的报错The packaging for this project did not assign a file to the build artifact
解决mvn clean install的报错The packaging for this project did not assign a file to the build artifact
- IDEA设置External Tools之Javap反编译字节码
通过Jdk的命令javap可以反编译查看字节码,但是在使用idea的时候一直用命令行去操作不太好操作,而且因为idea会把class码 放在target里面,经常会忘记切换目录.这个时候idea的Ex ...
- TP5发送邮件
1,前提去qq邮箱开启smtp 2,生成授权码 2,发送短信给 3,附上代码 贴上代码如下 <?phpnamespace app\mails\controller;use \think\Cont ...
- 多测师讲解内置函数 _format_高级讲师肖sir
#python中的格式化输出:format()# 和%号格式化输出一样,是%号的另外一种格式#1.不设置指定位置,按默认顺序 a ='{}'.format('hello','nihao','dajia ...
- 详解command设计模式,解耦操作和回滚
大家好,欢迎来到设计模式专题,我们的主旨是介绍一些有趣好玩的设计模式. 今天我们介绍的设计模式叫做命令模式(command),在这个模式下,我们可以实现do和undo的解耦,让使用方不用关心内部的实现 ...
- localStorage使用小结
一.什么是localStorage.sessionStorage 在HTML5中,新加入了一个localStorage特性,这个特性主要是用来作为本地存储来使用的,解决了cookie存储空间不足的问题 ...
- CentOS 7操作系统基础优化介绍
01 前言 操作系统部署完毕后,需要做一些基础的简单优化操作,可以为系统未来的使用过程带来更多便捷. 02 操作系统安全优化配置 系统安装完毕后,默认系统中会存在两个重要的安全服务程序,建议将其首先进 ...