zoukankan      html  css  js  c++  java
  • 左偏树

    思想

    这是一种支持合并操作的堆,实现起来很简单

    对于每一个节点,拥有一个dis值,即到儿子的最短距离

    其具有左偏性质:左二子的dis值大于右儿子的dis值

    由于此性质,保证了合并的时间复杂度是o(logn)的

    每次合并时,沿着两个堆的右子树进行

    每次合并其中一个的右子树和另外一个堆

    代码

    #include<bits/stdc++.h>
    const int maxn=300000;
    int v[maxn],fa[maxn],left1[maxn],right1[maxn],dis[maxn],id,xx,yy,x,y,n,m;
    using namespace std;
    int getfa(int x)
    { 
      while (fa[x]!=0) x=fa[x];
        return(x);
    };
    int merge(int r1,int r2)
    {
        if (r1==0 or r2==0) return(r1+r2);
        if (v[r1]>v[r2] or v[r1]==v[r2] and r1>r2) swap(r1,r2);
        right1[r1]=merge(right1[r1],r2);
        fa[right1[r1]]=r1;
        if (dis[left1[r1]]<dis[right1[r1]]) swap(left1[r1],right1[r1]);
        dis[r1]=dis[right1[r1]]+1;
        return(r1);
    };
    void delete1(int r1)
    {
        v[r1]=-1;
        fa[left1[r1]]=0; fa[right1[r1]]=0;
        merge(left1[r1],right1[r1]);
    };
    int main(){
        freopen("noip.in","r",stdin);
        freopen("noip.out","w",stdout);
      cin>>n>>m;
      for (int i=1; i<=n; i++) cin>>v[i];
      for (int i=1; i<=m; i++){
          cin>>id;
          if (id==1) 
            {
            cin>>x>>y;
            if (v[x]==-1 or v[y]==-1) continue;
            xx=getfa(x); yy=getfa(y);
            if (xx!=yy) merge(xx,yy);
          } else
            {
            cin>>x;
                if (v[x]==-1) 
                {
                     cout<<"-1"<<endl;
                     continue; 
              }
              xx=getfa(x);
              cout<<v[xx]<<endl;
              delete1(xx);
          }
      }  
      return(0);
    } 
  • 相关阅读:
    独立集
    密码
    【题解】[WC2006]水管局长
    【题解】[USACO12JAN]视频游戏的连击Video Game Combos
    【题解】HAOI2012高速公路
    【题解】洛谷P2418 yyy loves OI IV
    【题解】HNOI2008GT考试
    【哈哈哈哈】单词本
    【题解】CQOI2015任务查询系统
    【题解】洛谷P1975排序
  • 原文地址:https://www.cnblogs.com/yinwuxiao/p/7892913.html
Copyright © 2011-2022 走看看