传送门

如果一条边只要考虑 $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=0,f=1; char ch=getchar();while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }return x*f;
}
const int N=4e5+7,INF=1e9+7;
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][2],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][0],&rc=c[x][1];rev[x]=0; swap(lc,rc);if(lc) rev[lc]^=1;if(rc) rev[rc]^=1;
}
inline void rever(int x) { rev[x]^=1; pushdown(x); }
inline void pushup(int x)
{t[x]=x;if(val[ t[c[x][0]] ] > val[t[x]]) t[x]=t[c[x][0]];if(val[ t[c[x][1]] ] > val[t[x]]) t[x]=t[c[x][1]];
}
inline bool notroot(int x) { return (c[fa[x]][0]==x)|(c[fa[x]][1]==x); }
inline void rotate(int x)
{int y=fa[x],z=fa[y],d=(c[y][1]==x);if(notroot(y)) c[z][c[z][1]==y]=x;fa[x]=z; fa[y]=x; fa[c[x][d^1]]=y;c[y][d]=c[x][d^1]; c[x][d^1]=y;pushup(y); pushup(x);
}
inline void push_rev(int x)
{if(notroot(x)) push_rev(fa[x]);else pushdown(x);pushdown(c[x][0]); pushdown(c[x][1]);
}
inline void splay(int x)
{push_rev(x);while(notroot(x)){int y=fa[x],z=fa[y];if(notroot(y)){if(c[y][0]==x ^ c[z][0]==y) rotate(x);else rotate(y);}rotate(x);}
}
inline void access(int x)
{for(int y=0;x;y=x,x=fa[x])splay(x),c[x][1]=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][0]) pushdown(c[x][0]),x=c[x][0];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][0]) return;c[x][1]=fa[y]=0; pushup(x);
}
inline void query(int a)//更新答案
{if(findroot(1)==findroot(n))//如果在同一颗树上
    {int w=split(1,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=1;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更小才cutelse flag=0;//否则不连边
    }if(flag) link(n+i,x),link(n+i,y),query(a);//连边并更新ANS
}
int main()
{n=read(),m=read();for(int i=1;i<=m;i++)d[i].x=read(),d[i].y=read(),d[i].a=read(),d[i].b=read();sort(d+1,d+m+1);for(int i=1;i<=m;i++) val[n+i]=d[i].b;for(int i=1;i<=m;i++) insert(i);printf("%d",ANS <1e9 ? ANS : -1);return 0;
}

转载于:https://www.cnblogs.com/LLTYYC/p/10584416.html

P2387 [NOI2014]魔法森林相关推荐

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

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

  2. P2387 [NOI2014] 魔法森林

    简要题意: 给定一些无向边,每条边有 a a a 和 b b b 两个权值,要求判断能否到达终点 n n n ,能到达,就输出路径的最小的值,定义路径的最小值为这条路径上 a a a 和 b b b ...

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

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

  4. [LCT动态树] [NOI2014]魔法森林,[ZJOI2018]历史

    [NOI2014] 魔法森林 题目 按照aaa精灵从小到大排序 按顺序插入每一条边 加入第iii条边后的最小代价为a[i]a[i]a[i]加上从111到nnn的所有路径中最大bbb最小的路径代价 维护 ...

  5. loj2245 [NOI2014]魔法森林 LCT

    [NOI2014]魔法森林 链接 loj 思路 a排序,b做动态最小生成树. 把边拆成点就可以了. uoj98.也许lct复杂度写假了..越卡常,越慢 代码 #include <bits/std ...

  6. 【bzoj3669】[Noi2014]魔法森林【LCT】

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

  7. 神spfa [Noi2014]魔法森林

    问题 G: [Noi2014]魔法森林 时间限制: 30 Sec  内存限制: 512 MB 题目描述 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个 ...

  8. 【bzoj 3669】[Noi2014]魔法森林

    Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...

  9. 图论 BZOJ 3669 [Noi2014]魔法森林

    Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节 ...

最新文章

  1. apache配置反向代理以及实现url重写,防盗链
  2. pip安装 tensorflow-gpu 提示Could not install packages due to an EnvironmentError: [WinError 5] 拒绝访问
  3. r语言 c 函数返回值,R语言入门 输出函数 cat、print、paste等区别理解
  4. Altium Designer 的使用笔记
  5. Redhat的Linux产品版本AS/ES/WS的联系与区别
  6. 今晚直播丨Oracle DataGuard 备份恢复最佳实践
  7. elfutils库交叉编译
  8. linux删除文件未释放空间问题处理
  9. python实现简单的socket通信
  10. 最新python中一升级所有已安装的包方法
  11. 查询字符串(性能对比): Array Vs HashMap
  12. 小程序之校园交流平台
  13. 好女人是一所学校- -
  14. Ubuntu进入桌面后,左侧菜单栏和窗口菜单栏不见了的解决方法
  15. vivado ROM IP核简单使用
  16. Unity translucent SSS 次表面散射 皮肤材质研究
  17. Rai StudiesQuick Start Site for JAVA Developers
  18. win10中文输入法添加“美式键盘”布局
  19. html玫瑰花,HTML5 canvas绘制的玫瑰花效果
  20. 第一次使用Arduino MKR WIFI 1010

热门文章

  1. 李俊君信电保研面试发言稿及其分析总结
  2. TCP-Z V2.6.2 Build 20090409 (半开连接数监控与破解)
  3. mysql join查询
  4. windows平台下vlc编译之六:vlc-0.9.8a的编译
  5. 虚方法、重写方法和抽象方法[转载]
  6. Tech·Ed 2006博客园聚会
  7. mysql+1.6安装,CentOS 7.0编译安装Nginx1.6.0+MySQL5.6.19+PHP5.5.14方法
  8. 数字信道化中的兔耳效应
  9. C++中 gets()函数
  10. Word中“节”的作用