[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('\n');
        }
        else 
        {
            mergy(find(x),find(y));
        }
    }
    return 0;
}

诚恳地建议:

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

猜你喜欢

转载自www.cnblogs.com/xxzh/p/9571249.html