• 【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;
    }
  • 相关阅读:
    堆栈的分布
    Socket网络编程(TCP/IP/端口/类)和实例
    c语言字节对齐
    理一理字节对齐的那些事
    Socket网络编程(TCP/IP/端口/类)和实例
    socket、端口、进程的关系
    SMT32 启动文件详细解说
    Chapter 1 First Sight——22
    Leetcode389
    Chapter 1 First Sight——21
  • 原文地址:https://www.cnblogs.com/TSHugh/p/7341114.html
Copyright © 2020-2023  润新知