[BZOJ3669] [NOI2004] 魔法森林 LCT维护最小生成树
一开始看到这道题虽然知道是跟LCT维护最小生成树相关的但是没有可以的去想。
感觉可以先二分一下总的精灵数,但是感觉不太好做。
又感觉可以只二分一种精灵,用最小生成树算另一种精灵,但是和似乎不单调。
然后就可以自然地想到先把边按\(a\)从小到大加入,用LCT维护最小生成树,直接更新答案即可。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define REP(i,a,n) for(register int i(a);i<=(n);++i)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
#define lc t[o].c[0]
#define rc t[o].c[1]
const int SZ=(1<<21)+1;char ibuf[SZ],*iS,*iT,obuf[SZ+128],*oS=obuf,*oT=obuf+SZ-1;
#ifndef ONLINE_JUDGE
#define gc() getchar()
#else
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SZ,stdin),iS==iT?EOF:*iS++):*iS++)
#endif
template<typename I>inline void read(I&x){char c=gc();int f=1;for(;c<'0'||c>'9';c=gc())c=='-'?f=-1:0;for(x=0;c>='0'&&c<='9';c=gc())x=(x<<1)+(x<<3)+(c&15);f==-1?x=-x:0;}
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline char SMAX(A&a,const B&b){return a<b?a=b,1:0;}
template<typename A,typename B>inline char SMIN(A&a,const B&b){return a>b?a=b,1:0;}
const int N=50000+7,M=1e5+7;
int n,m,ans=0x3f3f3f3f;
struct Edges{int x,y,a,b;inline char operator<(const Edges&x)const{return a<x.a||(a==x.a&&b<x.b);}}e[M];//错误笔记:一定要加const!!!!
struct Node{int c[2],fa,v,max,pos,rev;}t[N+M];int S[N+M],top;
inline char Isroot(int o){return t[t[o].fa].c[0]!=o&&t[t[o].fa].c[1]!=o;}
inline char Identify(int o){return t[t[o].fa].c[1]==o;}
inline void Connect(int fa,int o,int d){t[fa].c[d]=o;t[o].fa=fa;}
inline void Pushup(int o){t[o].max=t[o].v;t[o].pos=o;if(SMAX(t[o].max,t[lc].max))t[o].pos=t[lc].pos;if(SMAX(t[o].max,t[rc].max))t[o].pos=t[rc].pos;}
inline void Rotate(int o){int fa=t[o].fa,pa=t[fa].fa,d1=Identify(o),d2=Identify(fa),b=t[o].c[d1^1];if(!Isroot(fa))t[pa].c[d2]=o;t[o].fa=pa;Connect(fa,b,d1);Connect(o,fa,d1^1);Pushup(fa),Pushup(o);}
inline void Pushdown(int o){if(t[o].rev){t[o].rev=0;if(lc)t[lc].rev^=1,std::swap(t[lc].c[0],t[lc].c[1]);if(rc)t[rc].rev^=1,std::swap(t[rc].c[0],t[rc].c[1]);}}
inline void Splay(int o){
int x=o;S[top=1]=x;while(!Isroot(x))S[++top]=x=t[x].fa;while(top)Pushdown(S[top--]);
while(!Isroot(o)){int fa=t[o].fa;if(Isroot(fa))Rotate(o);else if(Identify(o)==Identify(fa))Rotate(fa),Rotate(o);else Rotate(o),Rotate(o);}
}
inline void Access(int o){for(register int x=0;o;o=t[x=o].fa)Splay(o),rc=x,Pushup(o);}
inline void Makeroot(int o){Access(o);Splay(o);t[o].rev^=1;std::swap(lc,rc);}
inline int Findroot(int o){Access(o);Splay(o);while(lc)Pushdown(o),o=lc;Splay(o);return o;}
inline void Split(int x,int y){Makeroot(x);Access(y);Splay(y);}
inline void Link(int x,int y){Makeroot(x);if(Findroot(y)!=x)t[x].fa=y;}
inline void Cut(int x,int y){Split(x,y);if(t[y].c[0]&&!t[x].c[1])t[y].c[0]=t[x].fa=0;Pushup(y);}
int main(){
read(n),read(m);
REP(i,1,m)read(e[i].x),read(e[i].y),read(e[i].a),read(e[i].b);
std::sort(e+1,e+m+1);
REP(i,1,m){
const int&x=e[i].x,&y=e[i].y,&a=e[i].a,&b=e[i].b;
Makeroot(x);Access(y);Splay(x);const int d=t[x].max,p=t[x].pos;
if(Findroot(x)!=Findroot(y))t[i+n].v=t[i+n].max=b,t[i+n].pos=i+n,Link(e[i].x,i+n),Link(e[i].y,i+n);
else if(b<d)Cut(p,e[p-n].x),Cut(p,p[e-n].y),t[i+n].v=t[i+n].max=b,t[i+n].pos=i+n,Link(e[i].x,i+n),Link(e[i].y,i+n);
if(Findroot(1)==Findroot(n))Split(1,n),SMIN(ans,a+t[n].max);
}printf("%d\n",ans==0x3f3f3f3f?-1:ans);
}
[BZOJ3669] [NOI2004] 魔法森林 LCT维护最小生成树的更多相关文章
- P2387 [NOI2014]魔法森林 LCT维护最小生成树
\(\color{#0066ff}{ 题目描述 }\) 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐 士.魔法森林可以被看成一个包含 n 个节点 m 条边的无向图,节点标号为 ...
- bzoj3669: [Noi2014]魔法森林 lct版
先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...
- 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树
这道题看题意是在求一个二维最小瓶颈路,唯一可行方案就是枚举一维在这一维满足的条件下使另一维最小,那么我们就把第一维排序利用A小的边在A大的情况下仍成立来动态加边维护最小生成树. #include &l ...
- [Luogu P2387] [NOI2014]魔法森林 (LCT维护边权)
题面 传送门:https://www.luogu.org/problemnew/show/P2387 Solution 这题的思想挺好的. 对于这种最大值最小类的问题,很自然的可以想到二分答案.很不幸 ...
- Vijos1865 NOI2014 魔法森林 LCT维护生成树
基本思路: 首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值 如果加边过程中生成了环,则删除环中weightB最大的边 由于是无向图,点之间没有拓扑序, ...
- bzoj3669: [Noi2014]魔法森林 lct
记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸 然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以 ...
- [bzoj3669][Noi2014]魔法森林——lct
Brief description 给定一个无向图,求从1到n的一条路径使得这条路径上最大的a和b最小. Algorithm Design 以下内容选自某HN神犇的blog 双瓶颈的最小生成树的感觉, ...
- BZOJ 3669: [Noi2014]魔法森林(lct+最小生成树)
传送门 解题思路 \(lct\)维护最小生成树.我们首先按照\(a\)排序,然后每次加入一条边,在图中维护一棵最小生成树.用并查集判断一下\(1\)与\(n\)是否联通,如果联通的话就尝试更新答案. ...
- BZOJ2594 [Wc2006]水管局长数据加强版 【LCT维护最小生成树】
题目 SC省MY市有着庞大的地下水管网络,嘟嘟是MY市的水管局长(就是管水管的啦),嘟嘟作为水管局长的工作就是:每天供水公司可能要将一定量的水从x处送往y处,嘟嘟需要为供水公司找到一条从A至B的水管的 ...
随机推荐
- Linux内核设计与实现 总结笔记(第七章)中断和中断处理
中断和中断处理 处理器的速度跟外围硬件设备的速度往往不再一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求. 然后专门等待回应的办法,如果专门等待回应,明显太慢.所以等待期间可以处理其他事务, ...
- 【HDOJ6616】Divide the Stones(构造)
题意:给定n堆石子,第i堆的个数为i,要求构造出一种方案将其分成k堆,使得这k堆每堆数量之和相等且堆数相等 保证k是n的一个约数 n<=1e5 思路:先把非法的情况判掉 n/k为偶数的方法及其简 ...
- django正常运行确报错的解决方法
django正常运行却报错的处理方法 出处 : https://www.infvie.com/ops-notes/django-normal-operation-error 报错一:self._soc ...
- 20180824-Java Enumeration 接口
Java Enumeration接口 Enumeration接口中定义了一些方法,通过这些方法可以枚举(一次获得一个)对象集合中的元素. 这种传统接口已被迭代器取代,虽然Enumeration 还未被 ...
- Ponds
Ponds Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Sub ...
- Altium Designer chapter5总结
PCB设计环境中需要注意的如下: (1)PCB设计步骤:绘制原理图和生成网表—规划电路板—载入网表—元件布局—制定设计规则—布线—后期处理—DRC检查—信号完整性分析—gerbera文件输出 (2)P ...
- (经典文章uplink)Information capacity and power control in single-cell multiuser communications(1995)
摘要:本文在用户衰落被完美测量的情况下,提出一种可最大程度提高单小区多用户通信平坦衰落的信息容量的功率控制.主要特征为:在任何特定的时刻,只有一个用户在整个带宽上进行传输,并且在信道良好时为用户分配更 ...
- 洛谷P2786 英语1(eng1)- 英语作文——map
给一手链接 https://www.luogu.com.cn/problem/P2786 拿这道题当map模板练练手qwq #include<cstdio> #include<cst ...
- vue手写轮播
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 什么是HTTP协议?常用的状态码有哪些?
一.HTTP简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的 ...