模板 - FQH - treap 非旋平衡树

整理的算法模板合集: ACM模板

FQH - treap 非旋平衡树


operator 1 : 插入一个数
operator 2 : 删除一个数
operator 3 : 通过数值找排名
operator 4 : 通过排名找数值
operator 5 : 找到严格小于key的最大数(前驱)
operator 6 : 找到严格大于key的最小数(后继)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<time.h>
using namespace std;

const int N = 500007;

namespace treap{//!FHQ_Treap
    struct node{
        int l, r;
        int size;
        int val, fix;
    }tr[500007];
    int tot;
    int x, y, z, root;

    inline void pushup(int p)
    {
        tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + 1;
    }

    inline int get_node(int val)
    {
        tr[ ++ tot].size = 1;
        tr[tot].val = val;
        tr[tot].fix = rand();
        return tot;
    }

    inline int merge(int x, int y)
    {
        if(!x || !y)return x + y;
        if(tr[x].fix > tr[y].fix){
            tr[x].r = merge(tr[x].r, y);pushup(x);return x;}
        else {tr[y].l = merge(x, tr[y].l);pushup(y);return y;}
    }
    //x <= k y > k
    inline void split(int p, int k, int &x, int &y)//!xy最开始是谁无所谓,拆完之后要用谁而已
    {
        if(!p) {x = y = 0;return ;}
        if(tr[p].val <= k) x = p, split(tr[p].r, k, tr[p].r, y);
        else y = p, split(tr[p].l, k, x, tr[p].l);
        pushup(p);
    }

    inline int k_th(int p, int k)//找到第k个数的编号
    {
        while(1){
            if(k <= tr[tr[p].l].size)p = tr[p].l;
            else if(k == tr[tr[p].l].size + 1)return p;
            else k -= tr[tr[p].l].size + 1, p = tr[p].r;
        }
    }

    inline void ins(int k)
    {
        split(root, k, x, y);
        root = merge(merge(x, get_node(k)), y);
    }

    inline void del(int k)
    {
        split(root, k, x, z);
        split(x, k - 1, x, y);
        y = merge(tr[y].l, tr[y].r);
        root = merge(merge(x, y), z);
    }

    inline void get_rank(int k)
    {
        split(root, k - 1, x, y);
        printf("%d\n", tr[x].size + 1);
        root = merge(x, y);
    }

    inline void get_key(int k)
    {
        printf("%d\n", tr[k_th(root, k)].val);
    }

    inline void get_prev(int k)
    {
        split(root, k - 1, x, y);
        printf("%d\n", tr[k_th(x, tr[x].size)].val);
        root = merge(x, y);
    }

    inline void get_next(int k)
    {
        split(root, k, x, y);
        printf("%d\n", tr[k_th(y, 1)].val);
        root = merge(x, y);
    }
    inline void main(){
        srand((unsigned)time(NULL));
        memset(tr, 0, sizeof tr);
    }
}

int T;
int op, a;

int main()
{

    scanf("%d", &T);
    treap::main();
    while(T -- ){
        scanf("%d%d", &op, &a);
        if(op == 1)treap::ins(a);
        else if(op == 2)treap::del(a);
        else if(op == 3)treap::get_rank(a);
        else if(op == 4)treap::get_key(a);
        else if(op == 5)treap::get_prev(a);
        else treap::get_next(a);
    }
    return 0;
}

文艺平衡树

维护一个有序序列,经过m次区间操作:翻转一个区间,例如原有序序列是 5   4   3   2   1 5\ 4\ 3\ 2\ 1 ,翻转区间是 [ 2 , 4 ] [2,4] 的话,结果是 5   2   3   4   1 5\ 2\ 3\ 4\ 1 ,要求最后输出整个序列

/*平衡树实际上画出来是一颗乱糟糟的小根堆,但是满足小根堆的性质,
所以我们这里区间翻转,找到区间需要按照排名split,
只需要在这个区间里一直交换左右儿子即可实现区间翻转*/
/*最后中序遍历输出值即可*/
#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 500007;

int n, m, root;

namespace treap{

    int n, m, tot;

    struct tree{
        int l, r;
        int fix;
        int val;
        int size;
        int lz;
    }tr[500007];

    inline int get_node(int v)
    {
        tr[++ tot].val = v;
        tr[tot].size = 1;
        tr[tot].fix = rand();
        return tot;
    }

    void pushdown(int p)//下传懒标记,注意先交换,再下传
    {
        if(tr[p].lz){
            swap(tr[p].l, tr[p].r);
            tr[tr[p].l].lz ^= 1;
            tr[tr[p].r].lz ^= 1;
            tr[p].lz = 0;
        }
    }

    void pushup(int p)
    {
        tr[p].size = tr[tr[p].l].size + tr[tr[p].r].size + 1;
    }

    void split(int p, int rnk, int &x, int &y)
    {
        if(!p){x = y = 0;return ;}
        pushdown(p);
        //合并左边,往右边走
        if(tr[tr[p].l].size + 1 <= rnk)x = p,split(tr[p].r, rnk - tr[tr[p].l].size - 1, tr[p].r, y);
        else y = p, split(tr[p].l, rnk, x, tr[p].l);
        pushup(p);
    }

    int merge(int x, int y)
    {
        if(!x || !y)return x + y;
        if(tr[tr[x].l].fix < tr[tr[y].l].fix)
        {
            pushdown(x);
            tr[x].r = merge(tr[x].r, y);
            pushup(x);
            return x;
        }
        else {
            pushdown(y);
            tr[y].l = merge(x, tr[y].l);
            pushup(y);
            return y;
        }
    }

    void print(int p)//必须要中序遍历才能输出答案
    {
        pushdown(p);

        if(tr[p].l)//左
            print(tr[p].l);
        printf("%d ",tr[p].val);//中
        if(tr[p].r)//右
            print(tr[p].r);
    }
}

int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++ i)
    {
        root = treap::merge(root, treap::get_node(i));
    }
    for(int i = 1, l, r, x, y, p; i <= m; ++ i)
    {
        scanf("%d%d", &l, &r);
        treap::split(root, r, x, y);
        treap::split(x, l - 1, x, p);
        treap::tr[p].lz ^= 1;
        root = treap::merge(treap::merge(x, p), y);
    }
    treap::print(root);
    return 0;
}


可持久化序列

求支持三个操作:
1 l r,翻转l到r的区间;
2 l r,询问l的到r的区间和;
3 p,回到p时刻。
每次修改新建点打翻转标记即可

#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<algorithm>
using namespace std;
typedef pair<int,int> Pair;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=5e4+5;
const int nlogn=1.3e7+5;
struct node {
    int x,hp,l,r,sum,size;
    bool rev;
    void clear() {
        x=hp=l=r=sum=size=rev=0;
    }
};
struct TREAP {
    int pool[nlogn];
    int pooler;
    node t[nlogn];
    int now,all;
    int root[maxn];
    TREAP ():now(0),pooler(1) {
        for (int i=1;i<nlogn;++i) pool[i]=i;
        root[now]=pool[pooler++];
    }
    int newroot() {
        int ret=pool[pooler++];
        return ret;
    }
    int newnode(int x) {
        int ret=pool[pooler++];
        t[ret].hp=rand();
        t[ret].size=1;
        t[ret].x=t[ret].sum=x;
        return ret;
    }
    void delnode(int x) {
        t[x].clear();
        pool[--pooler]=x;
    }
    void next() {
        root[++all]=newroot();
        t[root[all]]=t[root[now]];
        now=all;
    }
    void back(int x) {
        now=x;
    }
    void update(int x) {
        t[x].sum=t[x].x+t[t[x].l].sum+t[t[x].r].sum;
        t[x].size=t[t[x].l].size+t[t[x].r].size+1;
    }
    void pushdown(int x) {
        if (!t[x].rev) return;
        if (t[x].l) {
            int tx=newnode(t[t[x].l].x);
            t[tx]=t[t[x].l];
            t[tx].rev^=true;
            t[x].l=tx;
        }
        if (t[x].r) {
            int tx=newnode(t[t[x].r].x);
            t[tx]=t[t[x].r];
            t[tx].rev^=true;
            t[x].r=tx;
        }
        swap(t[x].l,t[x].r);
        t[x].rev=false;
    }
    int merge(int x,int y) {
        if (!x) return y;
        if (!y) return x;
        int now;
        if (t[x].hp<=t[y].hp) {
            now=newnode(t[x].x);
            t[now]=t[x];
            pushdown(now);
            t[now].r=merge(t[now].r,y);
        } else {
            now=newnode(t[y].x);
            t[now]=t[y];
            pushdown(now);
            t[now].l=merge(x,t[now].l);
        }
        update(now);
        return now;
    }
    Pair split(int x,int p) {
        if (t[x].size==p) return make_pair(x,0);
        int now=newnode(t[x].x);
        t[now]=t[x];
        pushdown(now);
        int l=t[now].l,r=t[now].r;
        if (t[l].size>=p) {
            t[now].l=0;
            update(now);
            Pair g=split(l,p);
            now=merge(g.second,now);
            return make_pair(g.first,now);
        } else if (t[l].size+1==p) {
            t[now].r=0;
            update(now);
            return make_pair(now,r);
        } else {
            t[now].r=0;
            update(now);
            Pair g=split(r,p-t[l].size-1);
            now=merge(now,g.first);
            pushdown(now);
            return make_pair(now,g.second);
        }
    }
    void rever(int l,int r) {
        ++l,++r;
        Pair g=split(root[now],l-1);
        Pair h=split(g.second,r-l+1);
        int want=h.first;
        int here=newnode(t[want].x);
        t[here]=t[want];
        t[here].rev^=true;
        int fi=merge(g.first,here);
        int se=merge(fi,h.second);
        root[now]=se;
    }
    int query(int l,int r) {
        ++l,++r;
        Pair g=split(root[now],l-1);
        Pair h=split(g.second,r-l+1);
        int want=h.first;
        int ret=t[want].sum;
        int fi=merge(g.first,want);
        int se=merge(fi,h.second);
        root[now]=se;
        return ret;
    }
    void insert(int x) {
        int k=newnode(x);
        root[now]=merge(root[now],k);
    }
} Treap;
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
    freopen("my.out","w",stdout);
#endif
    srand(time(0));
    int n=read(),m=read();
    for (int i=1;i<=n;++i) {
        int x=read();
        Treap.insert(x);
    } 
    while (m--) {
        int op=read();
        if (op==1) {
            Treap.next();
            int l=read(),r=read();
            Treap.rever(l,r);
        } else if (op==2) {
            int l=read(),r=read();
            int ans=Treap.query(l,r);
            printf("%d\n",ans);
        } else if (op==3) {
            Treap.back(read());
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45697774/article/details/108160956