传送门

如果一条边只要考虑 $a$ 的限制,那么显然最小生成树

但是现在有 $a,b$ 两个限制,所以考虑按 $a$ 从小到大枚举边,动态维护 $b$ 的最小生成树

考虑新加入的一条边 $x,y$ ,如果 $x,y$ 不在一颗树上显然直接加入,如果在一棵树上,考虑原本树上 $x$ 到 $y$ 的路径上 $b$ 最大的边

如果比当前边大,那么就把原本那条边从最小生成树上删除,把新的边加进去

答案就在每次加边时更新就好了

这个东西显然直接 $LCT$ 维护,为了维护边权所以要把边权也看成点

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=4e5+,INF=1e9+;
int n,m,ANS=INF;
struct dat{
int x,y,a,b;
inline bool operator < (const dat &tmp) const {
return a<tmp.a;
}
}d[N];
int c[N][],fa[N],t[N],val[N];
//把边化成点后,t维护点权最大的点的编号,val[x]存点x的b值
//边的编号为n+1到n+m
bool rev[N];
inline void pushdown(int x)
{
if(!rev[x]||!x) return;
int &lc=c[x][],&rc=c[x][];
rev[x]=; swap(lc,rc);
if(lc) rev[lc]^=;
if(rc) rev[rc]^=;
}
inline void rever(int x) { rev[x]^=; pushdown(x); }
inline void pushup(int x)
{
t[x]=x;
if(val[ t[c[x][]] ] > val[t[x]]) t[x]=t[c[x][]];
if(val[ t[c[x][]] ] > val[t[x]]) t[x]=t[c[x][]];
}
inline bool notroot(int x) { return (c[fa[x]][]==x)|(c[fa[x]][]==x); }
inline void rotate(int x)
{
int y=fa[x],z=fa[y],d=(c[y][]==x);
if(notroot(y)) c[z][c[z][]==y]=x;
fa[x]=z; fa[y]=x; fa[c[x][d^]]=y;
c[y][d]=c[x][d^]; c[x][d^]=y;
pushup(y); pushup(x);
}
inline void push_rev(int x)
{
if(notroot(x)) push_rev(fa[x]);
else pushdown(x);
pushdown(c[x][]); pushdown(c[x][]);
}
inline void splay(int x)
{
push_rev(x);
while(notroot(x))
{
int y=fa[x],z=fa[y];
if(notroot(y))
{
if(c[y][]==x ^ c[z][]==y) rotate(x);
else rotate(y);
}
rotate(x);
}
}
inline void access(int x)
{
for(int y=;x;y=x,x=fa[x])
splay(x),c[x][]=y,pushup(x);
}
inline void makeroot(int x) { access(x); splay(x); rever(x); }
inline int findroot(int x)
{
access(x); splay(x); pushdown(x);
while(c[x][]) pushdown(c[x][]),x=c[x][];
splay(x);
return x;
}
inline int split(int x,int y) { makeroot(x); access(y); splay(y); return t[y]; }//提取一段路径上点权最大的点的编号
inline void link(int x,int y) { makeroot(x); if(findroot(y)!=x) fa[x]=y; }
inline void cut(int x,int y)
{
makeroot(x);
if(findroot(y)!=x||fa[y]!=x||c[y][]) return;
c[x][]=fa[y]=; pushup(x);
}
inline void query(int a)//更新答案
{
if(findroot()==findroot(n))//如果在同一颗树上
{
int w=split(,n);
ANS=min(ANS,a+val[w]);
}
}
inline void insert(int i)//加入边
{
int x=d[i].x,y=d[i].y,a=d[i].a,b=d[i].b; bool flag=;
if(findroot(x)==findroot(y))//如果原本已经是一颗树
{
int w=split(x,y);
if(val[w]>b) cut(w,d[w-n].x),cut(w,d[w-n].y);//如果b更小才cut
else flag=;//否则不连边
}
if(flag) link(n+i,x),link(n+i,y),query(a);//连边并更新ANS
}
int main()
{
n=read(),m=read();
for(int i=;i<=m;i++)
d[i].x=read(),d[i].y=read(),d[i].a=read(),d[i].b=read();
sort(d+,d+m+);
for(int i=;i<=m;i++) val[n+i]=d[i].b;
for(int i=;i<=m;i++) insert(i);
printf("%d",ANS <1e9 ? ANS : -);
return ;
}

P2387 [NOI2014]魔法森林的更多相关文章

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

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

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

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

  3. 洛谷P2387 [NOI2014]魔法森林(lct维护最小生成树)

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

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

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

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

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

  6. [Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)

    题面 传送门:https://www.luogu.org/problemnew/show/P2387 Solution 这题的思想挺好的. 对于这种最大值最小类的问题,很自然的可以想到二分答案.很不幸 ...

  7. 洛谷P2387 [NOI2014]魔法森林(LCT,Splay)

    在XZY&XZZ巨佬的引领下,一枚蒟蒻终于啃动了这道题...... 这次还是第一次写LCT维护边权,还要化边为点,思路乱七八糟的,写起来也不顺手,还好调了许久终于AC啦. 贪心排序按一个关键字 ...

  8. luogu P2387 [NOI2014]魔法森林

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

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

    在XZY&XZZ巨佬的引领下,一枚蒟蒻终于啃动了这道题...... 这次还是第一次写LCT维护边权,还要化边为点,思路乱七八糟的,写起来也不顺手,还好调了许久终于AC啦. 贪心排序按一个关键字 ...

随机推荐

  1. web优化

    一个小型的网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单.随着互联网业务的不断丰富,网站相关的技术经过 ...

  2. 线程dump

    当应用程序运行变慢或者发生故障时,可能通过分析java的Thread Dumps得到分析他们得到阻塞和存在瓶颈的线程. 线程堆栈是虚拟机中线程(包括锁)状态的一个瞬间状态的快照,即系统在某一个时刻所有 ...

  3. 解决0RA-04031故障

    1.客户反应报表数据很慢,简单查询5分钟都出不来. 2.登陆数据库服务器检查日志:Thu Mar 21 16:20:30 2013Errors in file /opt/oracle/diag/rdb ...

  4. Solidity 没名字的function(){...}作用

    官方解释: 这个叫做fallback function,当有人 1. 只发送以太币给合约而不带任何输入数据:2. 调用smart contract时调起了一个不存在的方法.会触发执行这个方法. Wha ...

  5. ssh时传递环境变量

    设置要传递的变量: -o SendEnv=Varname 但是不是每个都能传,受服务器上sshd_config里的下面两个选项的控制: AcceptEnv and PermitUserEnvironm ...

  6. 数字图像处理实验(14):PROJECT 06-01,Web-Safe Colors 标签: 图像处理MATLAB 2017-05-27 20:45 116人阅读

    实验要求: Objective: To know what are Web-safe colors, how to generate the RGB components for a given jp ...

  7. 各种RNAseq原理

    RNA Sequencing Methods Low-Level RNA Detection CEL-Seq CirSeq CLaP CytoSeq Digital RNA Sequencing DP ...

  8. 跨域问题hbuilder

    1.借助jquery-jsonp插件 $.jsonp({ url: url, data: { 'name': usd, 'passwd': pass }, callbackParameter: &qu ...

  9. PAT 1017 Queueing at Bank (25) (坑题)

    Suppose a bank has K windows open for service. There is a yellow line in front of the windows which ...

  10. js 简单抽奖实现

    大家在很多活动页面上都看到绚丽多彩的抽奖运用,网上也有比较多关于这方面的js和用as.今天我在工作的时候也要做个抽奖的运用.我之前没有写过这类的js,也不会as,就得屁颠屁颠的问度娘啦,虽然找到有js ...