来自蒟蒻 \(Hero \_of \_Someone\) 的 \(LCT\) 学习笔记
$
$
有一个很好的做法是 \(spfa\) ,但是我们不聊 \(spfa\) , 来聊 \(LCT\)
\(LCT\) 做法跟 \(spfa\) 的做法其实有点像,
先将所有的边按 \(a\) 的值从小到大排, 再以 \(b\) 的值为边权来动态的维护最小生成树,
答案即为 当前插入边的 \(a\) 值加上最小生成树中的最大边权 的最小值
$
$
此外, 用 \(LCT\) 维护 \(MST\) , 就是在添边的时候如果遇到环且环上最长的边边权大于当前边, 就将最大边 \(cut\) , 再将当前边添入

//made by Hero_of_Someone
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define N (50040)
#define M (100010)
#define RG register
using namespace std;
inline int gi(){ RG int x=0,q=1; RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  if(ch=='-') q=-1,ch=getchar(); while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=getchar(); return q*x; }
void File(){freopen(".in","r",stdin);freopen(".out","w",stdout);}

int n,m;
struct Edge{
  int u,v,a,b;
  bool operator<(const Edge& x)const{ return a<x.a; }
}e[M];

inline void init(){
  n=gi(),m=gi();
  for(RG int i=1;i<=m;i++){
    e[i].u=gi(),e[i].v=gi();
    e[i].a=gi(),e[i].b=gi();
  }
  sort(e+1,e+m+1);
}

int Max[N+M],val[N+M];
int ch[N+M][2],fa[N+M],rev[N+M];

inline void cur(int x,int y){ val[x]=Max[x]=y; }

inline bool cnm(int x,int y){ return e[x].b<e[y].b; }

inline void up(int x){
  Max[x]=max(Max[ch[x][0]],Max[ch[x][1]],cnm);
  Max[x]=max(Max[x],val[x],cnm);
}

inline void reverse(int x){
  swap(ch[x][0],ch[x][1]);
  rev[x]^=1;
}

inline void down(int x){
  if(!rev[x]) return ;
  reverse(ch[x][0]);
  reverse(ch[x][1]);
  rev[x]=0;
}

inline bool is_root(int x){ return ch[fa[x]][0]!=x && x!=ch[fa[x]][1]; }

inline bool lr(int x){ return x==ch[fa[x]][1]; }

inline void rotate(int x){
  RG int y=fa[x],z=fa[y],k=lr(x);
  if(!is_root(y)) ch[z][lr(y)]=x;
  fa[x]=z; fa[ch[x][k^1]]=y; fa[y]=x;
  ch[y][k]=ch[x][k^1]; ch[x][k^1]=y;
  up(y); up(x);
}

int st[N+M];
inline void splay(int x){
  RG int y=x,top=0;
  while(1){
    st[++top]=y;
    if(is_root(y)) break;
    y=fa[y];
  }
  for(RG int i=top;i;i--) down(st[i]);
  while(!is_root(x)){
    if(!is_root(fa[x])) rotate(lr(x)^lr(fa[x])?x:fa[x]);
    rotate(x);
  }
}

inline void access(int x){
  RG int y=0;
  while(x){ splay(x);
    ch[x][1]=y; fa[y]=x;
    up(x); y=x; x=fa[x];
  }
}

inline void make_root(int x){
  access(x); splay(x); reverse(x);
}

inline int find(int x){
  while(fa[x]) x=fa[x];
  return x;
}

inline void link(int x,int y){
  if(find(x)==find(y)) return ;
  make_root(x); fa[x]=y;
}

inline void cut(int x,int y){
  make_root(x); access(y); splay(y);
  if(ch[y][0]==x) ch[y][0]=0,fa[x]=0,up(y);
}

inline int query(int x,int y){
  make_root(x); access(y); splay(y);
  return Max[y];
}

inline void Insert(int id){
  RG int x=e[id].u,y=e[id].v;
  if(x==y) return ;
  if(find(x)==find(y)){
    RG int tmp=query(x,y);
    if(e[tmp].b<=e[id].b) return ;
    cut(n+tmp,e[tmp].u);
    cut(n+tmp,e[tmp].v);
  }
  cur(n+id,id);
  link(x,n+id);
  link(y,n+id);
}

inline void work(){
  RG int ans=1<<30;
  for(RG int i=1;i<=m;i++){
    Insert(i);
    if(find(1)!=find(n)) continue;
    ans=min(ans,e[i].a+e[query(1,n)].b);
  }
  if(ans==1<<30) ans=-1;
  printf("%d\n",ans);
}

int main(){ init(); work(); return 0; }

沉迷Link-Cut tree无法自拔之:[BZOJ3669][Noi2014] 魔法森林的更多相关文章

  1. bzoj3669: [Noi2014]魔法森林 lct版

    先上题目 bzoj3669: [Noi2014]魔法森林 这道题首先每一条边都有一个a,b 我们按a从小到大排序 每次将一条路劲入队 当然这道题权在边上 所以我们将边化为点去连接他的两个端点 当然某两 ...

  2. [bzoj3669][Noi2014]魔法森林_LCT_并查集

    魔法森林 bzoj-3669 Noi-2014 题目大意:说不明白题意系列++……题目链接 注释:略. 想法:如果只有1个参量的话spfa.dij什么的都上来了. 两个参量的话我们考虑,想将所有的边按 ...

  3. BZOJ3669[Noi2014]魔法森林——kruskal+LCT

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

  4. BZOJ3669: [Noi2014]魔法森林(瓶颈生成树 LCT)

    Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 3558  Solved: 2283[Submit][Status][Discuss] Descript ...

  5. BZOJ3669 [Noi2014]魔法森林(SPFA+动态加边)

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  6. bzoj3669[Noi2014]魔法森林

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  7. bzoj3669: [Noi2014]魔法森林 lct

    记得去年模拟赛的时候好像YY出二分答案枚举a,b的暴力,过了55欸 然后看正解,为了将两维变成一维,将a排序,模拟Kruskal的加边过程,同时维护1到n的最大值,加入一条边e(u,v,a,b)时有以 ...

  8. BZOJ3669 NOI2014魔法森林

    按a从小到大排序,然后按b建图. 每次只需要找1~n中最大的b加当前的a计算答案即可. 这里还有一个小操作就是化边为点,把一条边的边权看做一个点的点权然后多连两条边. By:大奕哥 #include& ...

  9. [bzoj3669][Noi2014]魔法森林——lct

    Brief description 给定一个无向图,求从1到n的一条路径使得这条路径上最大的a和b最小. Algorithm Design 以下内容选自某HN神犇的blog 双瓶颈的最小生成树的感觉, ...

随机推荐

  1. NOIP2018题解

    Preface 联赛结束后趁着自己还没有一下子把题目忘光,所以趁机改一下题目. 没有和游记一起写主要是怕篇幅太长不美观. 因此这里我们直接讲题目,关于NOIP2018的一些心得和有趣的事详见:NOIP ...

  2. 基于HTML5 Canvas的工控SCADA模拟飞机飞行

    昨天看到一篇文章说是学习如何开飞机的,然后我就想,如果我也可以开飞机那就好玩了,每个人小时候都想做飞行员!中国飞行员太难当了,再说也不轻易让你开飞机!后来我就想如果能用 HT 开飞机那就是真的有趣了, ...

  3. Azure Load Balancer : 支持 IPv6

    越来越多的网站开始支持 IPv6,即使是哪些只提供 api 服务的站点也需要支持 IPv6,比如苹果应用商店中的 app 早就强制要求服务器端支持 IPv6 了.笔者在前文<Azure Load ...

  4. ubuntu16.04在GTX1070环境下安装 cuda9.1

    设备要求 系统:Ubuntu16.04 显卡:GTX 1070 驱动:nvidia系列,显卡驱动的版本必须大于等于cuda的sh文件名里面的版本号 驱动可从 此处 下载,我已经整理好了 检查安装驱动 ...

  5. MySQL针对Swap分区的运维注意点

    Linux有很多很好的内存.IO调度机制,但是并不会适用于所有场景.对于运维人员来说,Linux比较让人头疼的一个地方是:它不会因为MySQL很重要就避免将分配给MySQL的地址空间映射到swap上. ...

  6. Spring RPC 入门学习(3)-获取Student对象

    Spring RPC传递对象. 1. 新建RPC接口:StudentInterface.java package com.cvicse.ump.rpc.interfaceDefine; import ...

  7. L2-027. 名人堂与代金券

    链接:名人堂与代金券 在比赛中这题只得了2分,赛后发现原来strcmp函数并不是只返回-1,0,1三种,而是返回正数负数0 但是在我的电脑上一般就是返回前三种,只是用后面的三种更稳妥点 都怪我基础不扎 ...

  8. Linux内核分析-系统中断在内核中的实现

    分析system_call中断处理过程 在MenuOS中添加上周所运用到的系统调用 即在Linuxkernel/menu/test.c文件中,添加代码如下: int Mkdir() { const c ...

  9. <四则运算>第二次冲刺

    这一次冲刺的主要内容是完善我们的界面,是我们的APP界面更规划更标准一点, 然后还要添加一些新算法. 距离客户的需求已经一半了. 代码正在完善中,稍后上传...

  10. SSM(Spring +SpringMVC + Mybatis)框架搭建

    SSM(Spring +SpringMVC + Mybatis)框架的搭建 最近通过学习别人博客发表的SSM搭建Demo,尝试去搭建一个简单的SSMDemo---实现的功能是对用户增删改查的操作 参考 ...