• 【BZOJ2733】永无乡(HNOI2012)-平衡树启发式合并


    测试地址:永无乡
    做法:本题需要用到平衡树启发式合并。
    题目要维护每个连通块的第k大,并且要支持合并。维护第k大我们知道可以用平衡树解决,但是平衡树的合并我们好像除了暴力就没有想法了。怎么样比较快地合并两棵平衡树?想法上非常简单,我们只需要暴力把点数比较小的那棵平衡树上的点一一插入到另一棵平衡树上。为什么这样就更优了呢?因为每次合并,新平衡树的大小必然是原小平衡树的两倍以上,那么每个元素就最多会被插入logn次,所以总的复杂度就是O(nlog2n)的,可以承受。
    好像根据某个定理,按小平衡树的中序遍历插入好像能达到O(nlogn)……虽然好像感觉没有变快,但应该还是能优化些常数的。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,q;
    int top[100010],fa[100010],ch[100010][2],key[100010],siz[100010];
    
    void pushup(int x)
    {
        siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    }
    
    void rotate(int x,bool f)
    {
        int y=fa[x];
        ch[y][!f]=ch[x][f];
        fa[ch[x][f]]=y;
        if (fa[y]) ch[fa[y]][ch[fa[y]][1]==y]=x;
        fa[x]=fa[y];
        fa[y]=x;
        ch[x][f]=y;
        pushup(y),pushup(x);
    }
    
    void Splay(int x,int &rt,int goal)
    {
        while(fa[x]!=goal)
        {
            if (fa[fa[x]]==goal) rotate(x,ch[fa[x]][0]==x);
            else
            {
                int y=fa[x],z=fa[fa[x]];
                bool f=(ch[y][1]==x);
                if (ch[z][f]==y) rotate(y,!f),rotate(x,!f);
                else rotate(x,!f),rotate(x,f);
            }
        }
        if (goal==0) rt=x;
    }
    
    int find_kth(int x,int k)
    {
        int rt;
        Splay(x,rt,0);
        if (siz[x]<k) return -1;
        while(siz[ch[x][0]]+1!=k)
        {
            int s=siz[ch[x][0]]+1;
            if (k<s) x=ch[x][0];
            else x=ch[x][1],k-=s;
        }
        Splay(x,rt,0);
        return x;
    }
    
    void insert(int &v,int &rt,int x,int f)
    {
        if (!v)
        {
            v=x;
            ch[v][0]=ch[v][1]=0;
            fa[v]=f;
            Splay(v,rt,0);
            return;
        }
        insert(ch[v][key[x]>key[v]],rt,x,v);
    }
    
    int find(int x)
    {
        int r=x,i=x,j;
        while(r!=top[r]) r=top[r];
        while(i!=r) {j=top[i],top[i]=r,i=j;}
        return r;
    }
    
    void order(int v,int &rty)
    {
        if (ch[v][0]) order(ch[v][0],rty);
        if (ch[v][1]) order(ch[v][1],rty);
        insert(rty,rty,v,0);
    }
    
    void merge(int x,int y)
    {
        int fx=find(x),fy=find(y),rt;
        top[fy]=fx;
        Splay(x,rt,0),Splay(y,rt,0);
        if (siz[x]>siz[y]) swap(x,y);
        order(x,y);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        siz[0]=0;
        for(int i=1;i<=n;i++)
        {
            top[i]=i;
            fa[i]=ch[i][0]=ch[i][1]=0;
            siz[i]=1;
            scanf("%d",&key[i]);
        }
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if (find(x)!=find(y)) merge(x,y);
        }
    
        scanf("%d",&q);
        while(q--)
        {
            char op[5];
            int x,y;
            scanf("%s%d%d",op,&x,&y);
            if (op[0]=='B'&&find(x)!=find(y)) merge(x,y);
            if (op[0]=='Q') printf("%d
    ",find_kth(x,y));
        }
    
        return 0;
    }
  • 相关阅读:
    变量
    python3基础知识
    __kindof的用法
    廖雪峰Python电子书总结
    解决嵌套在ScrollView中的TableView滑动手势冲突问题
    20180329-layoutSubviews的调用机制
    20180315-Python面向对象编程设计和开发
    20180308-Python内置方法
    20180306-time&datetime模块
    20180305-Python中迭代器和生成器
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793514.html
Copyright © 2020-2023  润新知