zoukankan      html  css  js  c++  java
  • [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;
    }

    诚恳地建议:

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

  • 相关阅读:
    Java自学-数组 创建数组
    Java自学-控制流程 结束外部循环
    Java自学-控制流程 break
    Java自学-控制流程 for
    Java自学-控制流程 continue
    Java自学-控制流程 switch
    Java自学-控制流程 If
    计算机组成原理之流水线处理器
    计算机组成原理之算术逻辑单元
    计算机组成原理之指令系统
  • 原文地址:https://www.cnblogs.com/xxzh/p/9571249.html
Copyright © 2011-2022 走看看