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

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

#include <cstdio>
#include <algorithm>
namespace Pre{
  inline void read(int &sum){
    register char ch=getchar();
    for(sum=0;ch<‘0‘||ch>‘9‘;ch=getchar());
    for(;ch>=‘0‘&&ch<=‘9‘;sum=(sum<<1)+(sum<<3)+ch-‘0‘,ch=getchar());
  }
  const int N=50010;
  const int M=100010;
  const int Inf=0x7f7f7f7f;
  int A[M],B[M],ans=Inf,X[M],Y[M],n,m,e[M];
  inline bool comp(int a,int b){
    return A[a]<A[b];
  }
  inline int Max(int x,int y){
    return x>y?x:y;
  }
  inline int Min(int x,int y){
    return x<y?x:y;
  }
}
namespace LCT{
  const int MN=150020;
  struct Node{
    Node *ch[2],*f;
    int id,rid;
    bool rev;
    inline void pushup(){
      using Pre::B;
      id=B[ch[0]->id]>B[ch[1]->id]?ch[0]->id:ch[1]->id;
      id=B[id]>B[rid]?id:rid;
    }
    inline void pushdown();
  }null[MN];
  inline void Swap(Node *&a,Node *&b){
    Node *c=a;
    a=b;
    b=c;
  }
  inline void Node:: pushdown(){
    if(!rev)return;
    Swap(ch[0],ch[1]);
    ch[0]->rev^=1;
    ch[1]->rev^=1;
    rev=0;
  }
  inline void Init(){
    using namespace Pre;
    null->ch[0]=null->ch[1]=null->f=null;
    for(int i=1;i<=n;i++)
      null[i].ch[0]=null[i].ch[1]=null[i].f=null,null[i].id=null[i].rid=0;
    for(int i=n+1;i<=n+m;i++)
      null[i].ch[0]=null[i].ch[1]=null[i].f=null,null[i].id=null[i].rid=i-n;
  }
  inline int get(Node *p){
    return p->f->ch[1]==p;
  }
  inline bool isroot(Node *p){
    return p->f->ch[0]!=p&&p->f->ch[1]!=p;
  }
  inline void rotate(Node *p){
    Node *fa=p->f,*pa=fa->f;
    int j=get(p);
    if(!isroot(fa))pa->ch[get(fa)]=p;
    if((fa->ch[j]=p->ch[j^1])!=null)fa->ch[j]->f=fa;
    fa->f=p;
    p->ch[j^1]=fa;
    p->f=pa;
    fa->pushup();
    p->pushup();
  }
  inline void spaly(Node *p){
    p->pushdown();
    for(Node *fa=p->f;!isroot(p);rotate(p),fa=p->f)
      if(!isroot(fa)){
        fa->f->pushdown(),fa->pushdown(),p->pushdown();
        rotate(get(fa)==get(p)?fa:p);
      }else
        fa->pushdown(),p->pushdown();
  }
  inline void expose(Node *p){
    Node *y=null;
    while(p!=null){
      spaly(p);
      p->ch[1]=y;
      p->pushup();
      y=p;
      p=p->f;
    }
  }
  inline void make_root(Node *p){
    expose(p);
    spaly(p);
    p->rev^=1;
  }
  inline Node *find_root(Node *p){
    expose(p);
    spaly(p);
    while(p->ch[0]!=null)
      p=p->ch[0],p->pushdown();
    return p;
  }
  inline void link(Node *a,Node *b){
    make_root(a);
    a->f=b;
  }
  inline void cut(Node *a,Node *b){
    make_root(a);
    expose(b);
    spaly(b);
    b->ch[0]->f=null;
    b->ch[0]=null;
    b->pushup();
  }
  inline void Link(int a,int b){
    link(null+a,null+b);
  }
  inline void Cut(int a,int b){
    cut(null+a,null+b);
  }
  inline int find(int x){
    return find_root(null+x)-null;
  }
  inline int query(int a,int b){
    Node *x=null+a,*y=null+b;
    make_root(x);
    expose(y);
    spaly(y);
    return Pre::B[y->id];
  }
  inline int query_id(int a,int b){
    Node *x=null+a,*y=null+b;
    make_root(x);
    expose(y);
    spaly(y);
    return y->id;
  }
}
inline void Init(){
  using namespace Pre;
  read(n),read(m);
  for(int i=1;i<=m;i++)
    read(X[i]),read(Y[i]),read(A[i]),read(B[i]),e[i]=i;
  std::sort(e+1,e+m+1,comp);
  LCT::Init();
}
inline void Work(){
  using namespace Pre;
  using LCT::find;
  using LCT::query;
  using LCT::Link;
  using LCT::Cut;
  using LCT::query_id;
  for(int i=1;i<=m;i++)
    if(find(X[e[i]])!=find(Y[e[i]])){
      Link(e[i]+n,X[e[i]]),Link(e[i]+n,Y[e[i]]);
      if(find(1)==find(n))
        ans=Min(query(1,n)+A[e[i]],ans);
    }else if(query(X[e[i]],Y[e[i]])>B[e[i]]){
      int temp=query_id(X[e[i]],Y[e[i]]);
      Cut(temp+n,X[temp]),Cut(temp+n,Y[temp]);
      Link(e[i]+n,X[e[i]]),Link(e[i]+n,Y[e[i]]);
      if(find(1)==find(n))
        ans=Min(ans,query(1,n)+A[e[i]]);
    }
}
int main(){
  using namespace Pre;
  Init(),Work();
  printf("%d",ans==Inf?-1:ans);
  return 0;
}
时间: 2024-11-03 20:54:09

【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树的相关文章

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

排序搞掉一维, 然后就用LCT维护加边MST. O(NlogN) -------------------------------------------------------------------------------------- #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1

bzoj 3669: [Noi2014]魔法森林 动态树

3669: [Noi2014]魔法森林 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 363  Solved: 202[Submit][Status] Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节点1,隐士则住在号节点N.小E需要通过这一片魔法森林,才能够拜访到隐士. 魔法森林中居住了一些妖怪

bzoj 3669: [Noi2014]魔法森林

3669: [Noi2014]魔法森林 Time Limit: 30 Sec  Memory Limit: 512 MB 动点spfa Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节点1,隐士则住在号节点N.小E需要通过这一片魔法森林,才能够拜访到隐士. 魔法森林中居住了一些妖怪.每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击.幸运的

BZOJ 3669 NOI2014 魔法森林 SPFA

题目大意: 给定一个无向图,每条边有两个权值ai和bi,从1走到N,设路径上a权的最大值为A,b权的最大值为B,求A+B的最小值 首先这题如果只有一个权值就是水题无误--但是多了个权值之后我们就要好好考虑一下了 我们对a排序,枚举a,对于每一次枚举求b权最大值的最小值即可 跑M遍SPFA肯定超时无误 网上很多人写了LInk-Cut-Tree维护动态最小生成树 我的LCT没写明白 就去写了SPFA.... 这里要用的SPFA的动态加点(边)法 我们每加一条边 就把边的两端点入队 继续SPFA 不用

[BZOJ 3669] [Noi2014] 魔法森林 【LCT】

题目链接:BZOJ - 3669 题目分析 如果确定了带 x 只精灵A,那么我们就是要找一条 1 到 n 的路径,满足只经过 Ai <= x 的边,而且要使经过的边中最大的 Bi 尽量小. 其实就是一个按照 Bi 建立的 MST 上 1 到 n 的路径.只能使用 Ai <= x 的边. 那么,如果我们从小到大枚举 x ,这样可以使用的边就不断增加,就是在加边的同时维护 MST ,用 LCT 来做就可以了. 如果新加入一条边 (u, v, w) ,并且原 MST 上 u 到 v 的路径中边权最大

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

基本思路: 首先按照weightA升序排序,然后依次在图中加边,并维护起点到终点路径上weightB的最大值 如果加边过程中生成了环,则删除环中weightB最大的边 由于是无向图,点之间没有拓扑序,所以在建立LCT模型时,可以将原图的边也视为点,这样就转化成了维护路径上的点权最大值(Orz Hzwer) 点的连通性可以用并查集维护 AC code:(其实Splay双旋一次时只需要进行3次update,而代码中舍弃了这个优化) 1 #include <cstdio> 2 #include &l

【BZOJ3669】[Noi2014]魔法森林 LCT

[BZOJ3669][Noi2014]魔法森林 Description 为了得到书法大家的真传,小E同学下定决心去拜访住在魔法森林中的隐士.魔法森林可以被看成一个包含个N节点M条边的无向图,节点标号为1..N,边标号为1..M.初始时小E同学在号节点1,隐士则住在号节点N.小E需要通过这一片魔法森林,才能够拜访到隐士. 魔法森林中居住了一些妖怪.每当有人经过一条边的时候,这条边上的妖怪就会对其发起攻击.幸运的是,在号节点住着两种守护精灵:A型守护精灵与B型守护精灵.小E可以借助它们的力量,达到自

【BZOJ】3669: [Noi2014]魔法森林(lct)

http://www.lydsy.com/JudgeOnline/problem.php?id=3669 首先看到题目应该可以得到我们要最小化 min{ max{a(u, v)} + max{b(u, v)} } 两个变量不好做...那么我们约束一个a 即按a从小到大排序,依次加边. 发现当有环出现时,去掉的是环中b最大的边. 证明:因为a是从小到大排序,因此此时答案为 a+max{b(u, v)},显然b越小越好. 然后需要link和cut操作... 脑洞开到这里开不动了...........

3669 [Noi2014]魔法森林(LCT,最小生成树)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3669 [题意] 给定一个无向图,求1-n的路径中最小的max{ai}+max{bi} [思路] 将边按照a排序.LCT维护关于b的最小生成树. 顺序枚举每条边u,v,如果u,v已经连接则比较u,v路径上的最大边与新边,否则直接相连. 如果1与n连通,则用e.a+max{e.b}更新ans.直观地看,最小生成树上的max{e.b}是1..i条边加入后能够得到的最小b. _max的初值赋