学习笔记::启发式合并

Posted 123456

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习笔记::启发式合并相关的知识,希望对你有一定的参考价值。

昨天做Tree Rotation,没发现自己写的是暴力,还要了数据。。。。。。

然后发现好像必须得用启发式合并

不想学线段树,学了个splay的

---------------------------------------------------

假设现在有n个点,每个点是一个splay,互不连起来

假设我们每次让两个不连通的splay联通,

所谓启发式:就是把小的合并到大的上,这样使复杂度有保证

怎么合并呢?就是先把小的splay的每个点找出来,然后插入到大的splay

---------------------------------------------------

这里我还理解了半天。。。

还以为跟可并堆什么的很像。。。没想到这么暴力(naive)

bzoj 2733

这道题我把Rank加反了,结果tle

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 400010
int n,m,Q;
int size[N],fa[N],key[N],father[N],Rank[N],q[N];
int child[N][2];
int read()
{
    int x=0,f=1; char c=getchar();
    while(c<\'0\'||c>\'9\') {if(c==\'-\') f=-1; c=getchar(); }
    while(c>=\'0\'&&c<=\'9\') {x*=10; x=x+c-\'0\'; c=getchar();}
    return x*f;
}
void update(int x)
{
    size[x]=size[child[x][0]]+size[child[x][1]]+1;
}
void zig(int x)
{
    int y=fa[x];
    fa[x]=fa[y]; child[fa[x]][child[fa[x]][1]==y]=x;
    child[y][0]=child[x][1]; fa[child[x][1]]=y;
    fa[y]=x; child[x][1]=y;
    update(y); update(x);
}
void zag(int x)
{
    int y=fa[x];
    fa[x]=fa[y]; child[fa[x]][child[fa[x]][1]==y]=x;
    child[y][1]=child[x][0]; fa[child[x][0]]=y;
    fa[y]=x; child[x][0]=y;
    update(y); update(x);
}
void splay(int x)
{
    while(fa[x])
    {
        int y=fa[x],z=fa[y];
        if(!z)
        {
            child[y][0]==x?zig(x):zag(x); break;
        }
        child[y][0]==x?zig(x):zag(x);
        child[z][0]==x?zig(x):zag(x);
    }
}
void insert(int x,int root)
{
    int y=root,last;
    while(y)
    {
        last=y;
        if(key[x]>key[y]) y=child[y][1];
        else y=child[y][0];
    }
    fa[x]=last;
    child[last][(key[x]>key[last])]=x;
    update(x); update(last);
    splay(x);
}
void merge(int x,int y)
{
    splay(x); splay(y);
    if(size[x]>size[y]) swap(x,y);
    int l=1,r=0;
    q[++r]=x;
    while(l<=r)
    {
        int u=q[l++];
        if(child[u][0]) q[++r]=child[u][0];
        if(child[u][1]) q[++r]=child[u][1];
    }
    q[0]=y;
    for(int i=1;i<=r;i++) insert(q[i],q[i-1]);
}
int findkth(int x,int k)
{
    if(size[child[x][0]]==k-1) return x;
    if(size[child[x][0]]+1>k) return findkth(child[x][0],k);
    else return findkth(child[x][1],k-size[child[x][0]]-1);
}
int find(int x)
{
    return father[x]==x?father[x]:find(father[x]);
}
void connect(int x,int y)
{
    int a=find(x),b=find(y);
    if(a==b) return;
    if(Rank[a]>=Rank[b])
    {
        Rank[a]+=Rank[b];
        father[b]=a;
    }
    else
    {
        Rank[b]+=Rank[a];
        father[a]=b;
    }
}
void link(int x,int y)
{
    if(find(x)==find(y)) return;
    merge(x,y);
    connect(x,y);
}
void query(int x,int k)
{
    splay(x);
    if(size[x]<k) 
    {
        printf("-1\\n");
        return;
    }
    printf("%d\\n",findkth(x,k));
}
int main()
{
    n=read(); m=read();
    for(int i=1;i<=n;i++)
    {
        key[i]=read();
        father[i]=i;
        Rank[i]=size[i]=1;
    }
    for(int i=1;i<=m;i++) 
    {
        int u,v; u=read(); v=read();
        if(u==0||v==0) continue;
        link(u,v);
    }
    Q=read();
    while(Q--)
    {
        char s[10]; int a,b; scanf("%s",s);
        a=read(); b=read();
        if(a==0||b==0) continue;
        if(s[0]==\'B\') link(a,b);
        if(s[0]==\'Q\') query(a,b);
    }
    return 0;
}
View Code

 

以上是关于学习笔记::启发式合并的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记::启发式合并

启发式合并(堆setsplaytreap)/线段树合并学习小记

学习笔记dsu on tree

学习笔记:python3,代码片段(2017)

bzoj2733 永无乡 splay树的启发式合并

bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)