• 【启发式合并】线段树,平衡树


    【启发式合并】线段树,平衡树

    启发式合并就是一种复杂度可以证明的贪心合并

    平衡树启发式合并:

    对于平衡树的启发式合并,我们将一个 $size$ 较小平衡树一个一个结点暴力加入 $size$ 较大的平衡树中

    最坏时间复杂度是玄学的 $O(N log^{2} N)$

    空间复杂度 $O(N)$

    模板题:P3224 [HNOI2012]永无乡

      1 #include<bits/stdc++.h>
      2 #define MAXN 100010
      3 using namespace std;
      4 inline int read ()
      5 {
      6     int s=0,w=1;
      7     char ch=getchar ();
      8     while (ch<'0'||ch>'9'){if (ch=='-') w=-1;ch=getchar ();}
      9     while ('0'<=ch&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar ();
     10     return s*w;
     11 }
     12 int n,m,q;
     13 int ch[MAXN][2],fa[MAXN],rk[MAXN];
     14 int Fa[MAXN],root[MAXN],size[MAXN];
     15 char opt[10];
     16 int find (int x)
     17 {
     18     if (Fa[x]!=x) Fa[x]=find (Fa[x]);
     19     return Fa[x];
     20 }
     21 int get (int x)
     22 {
     23     return ch[fa[x]][1]==x;
     24 }
     25 void update (int x)
     26 {
     27     size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
     28 }
     29 void rotate (int x)
     30 {
     31     int y=fa[x],z=fa[y],k=get (x);
     32     if (z) ch[z][get (y)]=x;fa[x]=z;
     33     ch[y][k]=ch[x][k^1];
     34     if (ch[x][k^1]) fa[ch[x][k^1]]=y;
     35     ch[x][k^1]=y;fa[y]=x;
     36     update (y),update (x);
     37 }
     38 void splay (int w,int x,int pos)
     39 {
     40     while (fa[x]!=pos)
     41     {
     42         int y=fa[x];
     43         if (fa[y]!=pos) rotate (get (x)==get (y)?y:x);
     44         rotate (x);
     45     }
     46     if (pos==0) root[w]=x;
     47 }
     48 void insert (int w,int k)
     49 {
     50     int ff,x=root[w];
     51     while (x)
     52     {
     53         ff=x;
     54         if (rk[k]<rk[x]) x=ch[x][0];
     55         else x=ch[x][1];
     56     }
     57     ch[ff][rk[k]>rk[ff]]=k,fa[k]=ff;
     58     splay (w,k,0);
     59 }
     60 void merge (int w,int x)
     61 {
     62     if (!x) return;
     63     merge (w,ch[x][0]);merge (w,ch[x][1]);
     64     fa[x]=ch[x][0]=ch[x][1]=0;
     65     insert (w,x);
     66 }
     67 int getkth (int w,int k)
     68 {
     69     int x=root[w];
     70     while (x)
     71     {
     72         if (size[ch[x][0]]+1==k) return splay (w,x,0),x;
     73         else if (size[ch[x][0]]>=k) x=ch[x][0];
     74         else k-=size[ch[x][0]]+1,x=ch[x][1];
     75     }
     76     return -1;
     77 }
     78 int main()
     79 {
     80     n=read (),m=read ();
     81     for (int i=1;i<=n;i++) rk[i]=read (),Fa[i]=i,root[i]=i,size[i]=1;
     82     for (int i=1;i<=m;i++)
     83     {
     84         int u=read (),v=read ();
     85         int r1=find (u),r2=find (v);
     86         if (r1!=r2)
     87         {
     88             if (size[root[r1]]>size[root[r2]]) swap (r1,r2);
     89             Fa[r1]=r2,merge (r2,root[r1]);
     90         }
     91     }
     92     q=read ();
     93     while (q--)
     94     {
     95         scanf ("%s",opt+1);
     96         if (opt[1]=='Q')
     97         {
     98             int x=read (),k=read ();
     99             printf ("%d
    ",getkth (find (x),k));
    100         }
    101         else
    102         {
    103             int u=read (),v=read ();
    104             int r1=find (u),r2=find (v);
    105             if (r1!=r2)
    106             {
    107                 if (size[root[r1]]>size[root[r2]]) swap (r1,r2);
    108                 Fa[r1]=r2,merge (r2,root[r1]);
    109             }
    110         }
    111     }
    112     return 0;
    113 }

    线段树合并

    我们使用动态开点线段树,我们按照 $dfs$ 的顺序,将每个子节点并到父节点上。线段树的下标一般就是要维护的值

    时间复杂度可以达到 $O(N log N)$,但空间复杂度为 $O(N log N)$

    模板题:P4556 [Vani有约会]雨天的尾巴

      1 #include<bits/stdc++.h>
      2 #define MAXN 100010
      3 using namespace std;
      4 inline int read ()
      5 {
      6     int s=0,w=1;
      7     char ch=getchar ();
      8     while (ch<'0'||ch>'9'){if (ch=='-') w=-1;ch=getchar ();}
      9     while ('0'<=ch&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar ();
     10     return s*w;
     11 }
     12 struct Node{
     13     int pos,val;
     14 };
     15 struct SEG{
     16     int l,r,id,num;
     17 }tr[MAXN*100];
     18 struct edge{
     19     int v,nxt;
     20 }e[MAXN<<1];
     21 int n,m,cnt,len,Maxz;
     22 int head[MAXN],ans[MAXN];
     23 int fa[MAXN],root[MAXN],son[MAXN],size[MAXN],top[MAXN],dep[MAXN];
     24 vector<Node>vec[MAXN];
     25 void add (int u,int v)
     26 {
     27     e[++cnt].v=v;
     28     e[cnt].nxt=head[u];
     29     head[u]=cnt;
     30 }
     31 void dfs1 (int u,int ff)
     32 {
     33     fa[u]=ff,dep[u]=dep[ff]+1,size[u]=1;
     34     for (int i=head[u];i!=0;i=e[i].nxt)
     35         if (e[i].v!=ff)
     36         {
     37             dfs1 (e[i].v,u);
     38             size[u]+=size[e[i].v];
     39             if (size[e[i].v]>size[son[u]]) son[u]=e[i].v;
     40         }
     41 }
     42 void dfs2 (int u,int topf)
     43 {
     44     top[u]=topf;
     45     if (son[u]) dfs2 (son[u],topf);
     46     for (int i=head[u];i!=0;i=e[i].nxt)
     47         if (!top[e[i].v])
     48             dfs2 (e[i].v,e[i].v);
     49 }
     50 int LCA (int x,int y)
     51 {
     52     while (top[x]!=top[y])
     53     {
     54         if (dep[top[x]]<dep[top[y]]) swap (x,y);
     55         x=fa[top[x]];
     56     }
     57     return dep[x]<dep[y]?x:y;
     58 }
     59 void pushup (int x)
     60 {
     61     int l=tr[x].l,r=tr[x].r;
     62     if (tr[l].num>tr[r].num||(tr[l].num==tr[r].num&&tr[l].id<tr[r].id))
     63         tr[x].num=tr[l].num,tr[x].id=tr[l].id;
     64     else tr[x].num=tr[r].num,tr[x].id=tr[r].id;
     65 }
     66 void update (int &x,int l,int r,int pos,int val)
     67 {
     68     if (!x) x=++len;
     69     if (l==r)
     70     {
     71         tr[x].id=pos,tr[x].num+=val;
     72         return;
     73     }
     74     int mid=(l+r)>>1;
     75     if (pos<=mid) update (tr[x].l,l,mid,pos,val);
     76     else update (tr[x].r,mid+1,r,pos,val);
     77     pushup (x);
     78 }
     79 int merge (int a,int b,int l,int r)
     80 {
     81     if (!a||!b) return a+b;
     82     if (l==r)
     83     {
     84         tr[a].num+=tr[b].num;
     85         return a;
     86     }
     87     int mid=(l+r)>>1;
     88     tr[a].l=merge (tr[a].l,tr[b].l,l,mid);
     89     tr[a].r=merge (tr[a].r,tr[b].r,mid+1,r);
     90     pushup (a);
     91     return a;
     92 }
     93 void dfs (int u,int ff)
     94 {
     95     for (int i=0;i<vec[u].size ();i++)
     96         update (root[u],1,Maxz,vec[u][i].pos,vec[u][i].val);
     97     for (int i=head[u];i!=0;i=e[i].nxt)
     98         if (e[i].v!=ff)
     99         {
    100             dfs (e[i].v,u);
    101             root[u]=merge (root[u],root[e[i].v],1,Maxz);
    102         }
    103     if (tr[root[u]].num==0) ans[u]=0;
    104     else ans[u]=tr[root[u]].id;
    105 }
    106 int main()
    107 {
    108     n=read (),m=read ();
    109     for (int i=1;i<n;i++)
    110     {
    111         int u=read (),v=read ();
    112         add (u,v);add (v,u);
    113     }
    114     dfs1 (1,0);
    115     dfs2 (1,1);
    116     while (m--)
    117     {
    118         int x=read (),y=read (),z=read (),lca=LCA (x,y);
    119         Maxz=max (Maxz,z);
    120         if (lca==x) vec[fa[x]].push_back (Node{z,-1}),vec[y].push_back (Node{z,1});
    121         else if (lca==y) vec[fa[y]].push_back (Node{z,-1}),vec[x].push_back (Node{z,1});
    122         else vec[fa[lca]].push_back (Node{z,-1}),vec[lca].push_back (Node{z,-1}),vec[x].push_back (Node{z,1}),vec[y].push_back (Node{z,1});
    123     }
    124     dfs (1,0);
    125     for (int i=1;i<=n;i++)
    126         printf ("%d
    ",ans[i]);
    127     return 0;
    128 }

    堆的启发式合并

    由于左偏树更加稳定,所以通常用不上

  • 相关阅读:
    Makefile学习笔记1
    Shell脚本学习笔记8——跳出循环
    Shell脚本学习笔记7——case...esac
    Shell脚本学习笔记6——循环语句
    Linux命令学习笔记3:touch命令
    Linux命令学习笔记2:ll命令
    Linux命令学习笔记1:ln命令
    Shell脚本学习笔记5——if条件语句
    Shell 脚本学习笔记4——Shell脚本中 '$' 符号的多种用法
    利用C++创建DLL并C#调用
  • 原文地址:https://www.cnblogs.com/PaulShi/p/10081749.html
Copyright © 2020-2023  润新知