题面

传送门: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维护边权)的更多相关文章

  1. P2387 [NOI2014]魔法森林 LCT维护最小生成树

    \(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...

  2. 洛谷P2387 [NOI2014]魔法森林(LCT)

    魔法森林 题目传送门 解题思路 把每条路按照\(a\)的值从小到大排序.然后用LCT按照b的值维护最小生成树,将边按照顺序放入.如果\(1\)到\(n\)有了一条路径,就更新最小答案.这个过程就相当于 ...

  3. luogu P2387 [NOI2014]魔法森林

    传送门 这题似乎不好直接做,可以考虑按照\(a_i\)升序排序,然后依次加边更新答案 具体实现方法是用lct维护当前的树,这里需要维护链上最大的\(b_i\).每次加一条边,如果加完以后没有环直接加, ...

  4. Vijos1865 NOI2014 魔法森林 LCT维护生成树

    基本思路: 首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值 如果加边过程中生成了环,则删除环中weightB最大的边 由于是无向图,点之间没有拓扑序, ...

  5. 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树

    这道题看题意是在求一个二维最小瓶颈路,唯一可行方案就是枚举一维在这一维满足的条件下使另一维最小,那么我们就把第一维排序利用A小的边在A大的情况下仍成立来动态加边维护最小生成树. #include &l ...

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

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

  7. 洛谷 P2387 [NOI2014]魔法森林 解题报告

    P2387 [NOI2014]魔法森林 题目描述 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 1,2 ...

  8. BZOJ 3669: [Noi2014]魔法森林( LCT )

    排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) ------------------------------------------------------------------- ...

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

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

随机推荐

  1. GTA5整合版

    GTA5mod整合版游戏介绍 GTA5mod整合版游戏是一款完美破解的游戏,玩家能够在游戏中享受最爽快的角色动作扮演玩法,在这里你将是一名强大的黑帮分子,在这个都市中,你将体验最真实的黑帮社会玩法.G ...

  2. linux_命令格式和命令提示符

    # linux 中一切皆文件 命令格式: 命令 [功能选项] [文件路径] cmd [options] [path] # 多个功能选项,要放在一起,如 rsync -avz /backup backu ...

  3. Appium的一些问题的总结答案

        问题 1. error: Failed to start an Appium session, err was: Error: Requested a new session but one ...

  4. mysql-13-auto_increment

    # 标识列 /* 自增长列 可以不用手动的插入值,系统提供默认的序列值 1.标识列必须和 key 搭配使用,比如主键.唯一键.外键 2.一个表至多一个标识列 3.标识列的类型只能是数值型 4.标识列可 ...

  5. 「面试」拿到B站的意向书

    此次B站服务端开发面试之旅可谓惊险,不过通过对大部分面试题套路的掌握,不出意外还是拿下了,下面我们来看看这些骚题是不是常见的不能再常见的了.这些面试题看了就能面上?当然不是,只是通过这些题让自己知道所 ...

  6. K8S环境的Jenkin性能问题处理续篇(任务Pod设置)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos K8S环境的Jenkin性能问题处理 本文是<K ...

  7. Flutter 1.22 正式发布

    支持iOS 14和Android 11,新的i18n和l10n支持,可用于生产的Google Maps和WebView插件,新的App Size工具等等! 作者:Chris Sells 原文:http ...

  8. 如何选择JVM垃圾回收器?

    明确垃圾回收器组合 -XX:+UseSerialGC 年轻代和老年代都用串行收集器 -XX:+UseParNewGC 年轻代使用ParNew,老年代使用 Serial Old -XX:+UsePara ...

  9. Centos7系统下Docker开启认证的远程端口2376配置教程

    docker开启2375会存在安全漏洞 暴露了2375端口的Docker主机.因为没有任何加密和认证过程,知道了主机IP以后,,任何人都可以管理这台主机上的容器和镜像,以前贪图方便,只开启了没有认证的 ...

  10. 用pChart生成雷达图图片

    需求 :由于工作需要,需要在一张背景图上添加这一张雷达图,之后图片可以在微信中长按保存.所以说我必须生成一张带有雷达图的图片第一反应是用百度echars雷达图做动态显示,之后截图.考虑到工作量和效率, ...