[HNOI2012]永无乡——Splay

题面

  Bzoj2733

解析

  同样是一道上课时讲的题, 对于每个连通块都维护一个Splay, 连接不同块的操作就等价于合并两棵Splay, 考虑暴力合并, 将较小的Splay断开,依次将每个点插入另外一棵Splay中, 复杂度的话,就照搬wys的PPT了:

[HNOI2012]永无乡——Splay_第1张图片

  查找点所在平衡树的根就暴力查找,一直跳父亲,均摊(应该是吧)跳log次找到根

  然后就变成了一道查询第k小的普通平衡树了

  第一道一次AC的Splay的题,终于没有写成Spaly了, 不容易啊, 感动

 代码:

#include
using namespace std;
const int maxn = 100005;

template<class T> void read(T &re)
{
    re=0;
    T sign=1;
    char tmp;
    while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;
    re=tmp-'0';
    while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=(re<<3)+(re<<1)+(tmp-'0');
    re*=sign;
}

int n, m, q, root[maxn], a[maxn], tot;

struct splay_tree{
    int s[2], val, fa, siz;
}tr[maxn];

int Find(int x)
{
    while(tr[x].fa != 0)
        x = tr[x].fa;
    root[x] = x;
    return x;
}

void update(int x)
{
    int ls = tr[x].s[0], rs = tr[x].s[1];
    tr[x].siz = tr[ls].siz + tr[rs].siz + 1;
}

void Rotate(int x)
{
    int y = tr[x].fa, z = tr[y].fa, k = (tr[y].s[1] == x), w = (tr[z].s[1] == y), son = tr[x].s[k^1];
    tr[y].s[k] = son;tr[son].fa = y;
    tr[x].s[k^1] = y;tr[y].fa = x;
    tr[z].s[w] = x;tr[x].fa = z;
    update(y);update(x);
}

void Splay(int x, int to, int id)
{
    int y, z;
    while(tr[x].fa != to)
    {
        y = tr[x].fa;z = tr[y].fa;
        if(z != to)
            Rotate((tr[y].s[0] == x) ^ (tr[z].s[0] == y)? x: y);
        Rotate(x);
    }
    if(!to)
        root[id] = x;
}

void Insert(int x, int y)
{
    int now = root[x], ff = 0;
    while(now)
    {
        tr[now].siz ++;
        ff = now;
        if(tr[y].val< tr[now].val)
            now = tr[now].s[0];
        else
            now = tr[now].s[1];
    }
    tr[ff].s[tr[y].val > tr[ff].val] = y;
    tr[y].s[0] = tr[y].s[1] = 0;
    tr[y].fa = ff;
    Splay(y, 0, x);
}

void Del(int x, int y)
{
    if(tr[y].s[0])
        Del(x, tr[y].s[0]);
    if(tr[y].s[1])
        Del(x, tr[y].s[1]);
    Insert(x, y);
}

int kth(int now, int x)
{
    while(1)
    {
        int ls = tr[now].s[0], rs = tr[now].s[1];
        if(x == tr[ls].siz + 1)     return now;
        if(x <= tr[ls].siz)     now = ls;
        else     x -= tr[ls].siz + 1, now = rs;
    }
}

int main()
{
    read(n);read(m);
    for(int i = 1; i <= n; ++i)
    {
        root[i] = ++tot;
        read(tr[root[i]].val);
        a[tr[root[i]].val] = i;
        tr[root[i]].siz = 1;
    }
    for(int i = 1; i <= m; ++i)
    {
        int x, y;
        read(x);read(y);
        int p = Find(x), q = Find(y);
        if(p != q)
        {
            if(tr[p].siz < tr[q].siz)
                swap(p, q);
            tr[0].s[1] = p;
            Del(p, q);
        }
    }
    read(q);
    for(int i = 1; i <= q; ++i)
    {
        char opt[5];
        int x, y;
        scanf("%s", opt);
        read(x);read(y);
        if(opt[0] == 'Q')
        {
            int p = Find(x);
            if(tr[p].siz < y)
                printf("-1\n");
            else
            {
                int id = kth(p, y);
                printf("%d\n", a[tr[id].val]);
                Splay(id, 0, p);
            }
        }
        else 
        {
            int p = Find(x), q = Find(y);
            if(p != q)
            {
                if(tr[p].siz < tr[q].siz)
                    swap(p, q);
                tr[0].s[1] = p;
                Del(p, q);
            }
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Joker-Yza/p/11236913.html

你可能感兴趣的:([HNOI2012]永无乡——Splay)