• [HNOI2012] 永无乡 解题报告 (splay+启发式合并)


    题目链接:https://www.luogu.org/problemnew/show/P3224#sub

    题目:

    题目大意:

    维护多个联通块,没有删除操作,每次询问某一联通块的第k大

    解法:

    维护联通块我们用并查集,询问第k大用splay,合并的时候splay暴力启发式合并就是了

    启发式合并:把size小的splay合并到size大的splay上,暴力插入就好了

    这道题的具体做法就是我们记录rt数组表示每个点的splay的根,在每次连边的时候就是把一方的根的所有节点全部插入到另一方的根去

    其他的可以参考我在洛谷的博客里写的东西:https://www.luogu.org/blog/xxzh2425/solution-p3224

    AC代码如下:

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cctype>
    #include<cstdlib>
    #define ri register int
    using namespace std;
    
    const int N=1e5+15;
    int n,m;
    int f[N],rt[N],w[N],fa[N];
    std::queue <int> dl;
    struct Splay
    {
        int ch[2];
        int ff,size;
    }t[N];
    inline int read()
    {
        char ch=getchar();
        int s=0,f=1;
        while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    inline int find(int x)
    {
        if (fa[x]!=x) fa[x]=find(fa[x]);
        return fa[x];
    }
    inline void pushup(int x)
    {
        t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
    }
    inline void rotate(int x)
    {
        int y=t[x].ff;
        int z=t[y].ff;
        int k=t[y].ch[1]==x;
        t[z].ch[t[z].ch[1]==y]=x;
        t[x].ff=z;
        t[y].ch[k]=t[x].ch[k^1];
        t[t[x].ch[k^1]].ff=y;
        t[x].ch[k^1]=y;
        t[y].ff=x;
        pushup(y);pushup(x);
    }
    inline void splay(int x,int goal)
    {
        while (t[x].ff!=goal)
        {
            int y=t[x].ff,z=t[y].ff;
            if (z!=goal) (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
            rotate(x);
        }
    }
    inline void insert(int x,int &now,int fat)
    {
        if (!now)
        {
            now=x;
            t[x].ff=fat;
            return;
        }
        t[now].ff=fat;
        t[now].size++;
        if (w[x]<=w[now]) insert(x,t[now].ch[0],now);
        else insert(x,t[now].ch[1],now);
    }
    inline void mergy(int x,int y)
    {
        if (x==y) return;
        if (t[rt[x]].size>t[rt[y]].size) std::swap(x,y);
        fa[rt[x]]=rt[y];
        dl.push(rt[x]);
        while (!dl.empty())
        {
            int k=dl.front();
            dl.pop();
            if (t[k].ch[0]) dl.push(t[k].ch[0]);
            if (t[k].ch[1]) dl.push(t[k].ch[1]);
            insert(k,rt[y],0);
            rt[k]=rt[y];
            //splay(k,rt[y]);
        }
    }
    inline int kth(int x,int k)
    {
        int now=rt[x];
        if (t[now].size<k) return -1;
        while (921)
        {
            if (t[t[now].ch[0]].size>=k) now=t[now].ch[0];
            else if (t[t[now].ch[0]].size+1==k) return now;
            else k-=t[t[now].ch[0]].size+1,now=t[now].ch[1];
        }
    }
    inline void write(int x)
    {
         if(x<0) putchar('-'),x=-x;
         if(x>9) write(x/10);
         putchar(x%10+'0');
    }
    int main()
    {
        n=read();m=read();
        for (ri i=1;i<=n;i++) 
        {
            w[i]=read();
            rt[i]=i;fa[i]=i;t[i].size=1;
        }
        for (ri i=1;i<=m;i++)
        {
            int u=read(),v=read();
            mergy(u,v);
        }
        int q=read();
        while (q--)
        {
            char ch=getchar();
            while (!(ch=='Q'||ch=='B')) ch=getchar();
            int x=read(),y=read();
            if (ch=='Q')
            {
                int ans=kth(find(x),y);
                write(ans);putchar('
    ');
            }
            else 
            {
                mergy(find(x),find(y));
            }
        }
        return 0;
    }

    诚恳地建议:

    去看看我在洛谷博客里写的东西

  • 相关阅读:
    基本数据类型和包装数据类型
    编程英语多样化(长期更新)
    jdk,jre,jvm,openJdk
    英语句子频率印象流
    单击单选按钮换成图片
    标签注意事项:
    背景图片处理
    天猫导航栏
    百度地图
    两栏布局
  • 原文地址:https://www.cnblogs.com/xxzh/p/9571249.html
Copyright © 2020-2023  润新知