P3391 【模板】文艺平衡树(Splay)
? 解题记录 ? ? 洛谷 ? ? Splay ? ? Treap ? ? 模板 ? ? 平衡树 ?    2017-11-22 23:30:14    495    0    0

题目背景

这是一道经典的Splay模板题——文艺平衡树。

题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

输入输出格式

输入格式:

 

第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2,n1,n) m表示翻转操作次数

接下来m行每行两个数 [l,r] 数据保证 1lrn

 

输出格式:

 

输出一行n个数字,表示原始序列经过m次变换后的结果

 

输入输出样例

输入样例#1: 复制
5 3
1 3
1 3
1 4
输出样例#1: 复制
4 3 2 1 5

说明

n,m100000

练习平衡树,为复习LCT做的准备。总的来说一个pushdown的平衡树是不难写的。不过有一个小技巧,先插入一个正无穷,一个负无穷可以减少很多操作。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x7fffffff;

namespace Splay {
    #define L 0
    #define R 1
    struct node {
        int ch[2], size, num, fa;
        bool rev;
    }tree[maxn];
    int root, cnt;
    
    void push_up(int rt) {
        int sz = tree[tree[rt].ch[R]].size + tree[tree[rt].ch[L]].size;
        tree[rt].size = sz + 1;
    }
    
    void push_down(int rt) {
        if(tree[rt].rev) {
            tree[tree[rt].ch[L]].rev ^= 1;
            tree[tree[rt].ch[R]].rev ^= 1;
            swap(tree[rt].ch[L], tree[rt].ch[R]);
            tree[rt].rev = 0;
        }
    }
    
    void rotate(int rt) {
        int p = tree[rt].fa;
        int a = tree[p].fa;
        int r = tree[p].ch[R] == rt, l = r ^ 1;
        if(a) tree[a].ch[tree[a].ch[R] == p] = rt;
        tree[rt].fa = a, tree[p].fa = rt, tree[tree[rt].ch[l]].fa = p;
        tree[p].ch[r] = tree[rt].ch[l], tree[rt].ch[l] = p;
        push_up(p), push_up(rt);
    }
    
    void splay(int rt, int y) {
        int des = tree[y].fa;
        while(tree[rt].fa != des) {
            int p = tree[rt].fa;
            int a = tree[p].fa;
            push_down(a), push_down(p), push_down(rt);
            if(p != y) {
                if((tree[a].ch[R] == p) ^ (tree[p].ch[R] == rt)) rotate(rt);
                else rotate(p);
            }
            rotate(rt);
        }
        if(y == root) root = rt;
    }
    
    void insert(int & rt, int num, int last) {
        if(!rt) {
            rt = ++cnt, tree[rt] = (node) {0, 0, 1, num, last};
            splay(rt, root);
            return ;
        }
        if(num > tree[rt].num) insert(tree[rt].ch[R], num, rt);
        else if(num < tree[rt].num) insert(tree[rt].ch[L], num, rt);
        else {
            ++tree[rt].size;
            splay(rt, root);
            return ;
        }
    }
    
    int qnum(int x){
        int now = root;
        push_down(now); 
        while(x > tree[tree[now].ch[L]].size + 1 || x <= tree[tree[now].ch[0]].size){
            int l = tree[now].ch[0];
            int r = tree[now].ch[1];
            if(tree[tree[now].ch[0]].size + 1 < x)    
                x -= (tree[tree[now].ch[0]].size + 1), now = r;
            else now = l;
            push_down(now);
        }
        return now;
    }
    
    void rev(int l, int r) {
        int ls = qnum(l);
        int rs = qnum(r + 2);
        splay(ls, root);
        splay(rs, tree[ls].ch[R]);
        tree[tree[rs].ch[L]].rev ^= 1;
    }
    
    void print(int rt) {
        push_down(rt);
        if(tree[rt].ch[L]) print(tree[rt].ch[L]);
        if(tree[rt].num != inf && tree[rt].num != -inf)
            printf("%d ", tree[rt].num);
        if(tree[rt].ch[R]) print(tree[rt].ch[R]);
    }
    
    void init(int n) {
        insert(root, -inf, 0);
        for(register int i = 1; i <= n; ++i)
            insert(root, i, 0);
        insert(root, inf, 0);
    }
}
int n, m, u, v;

int main() {
    scanf("%d%d", &n, &m);
    Splay::init(n);
    for(register int i = 1; i <= m; ++i){
        scanf("%d%d", &u, &v);
        Splay::rev(u, v);
    }
    Splay::print(Splay::root);
    return 0;
}

 

学习了非旋转式treap,重新写了这道题。

#include<cstdio>
#include<ctime>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int maxn = 1e5 + 5;
int n, m, a, b;
namespace Treap {
    struct node {
        int ch[2], key, size, num, rv;
    }tree[maxn];
    const int L = 0, R = 1;
    int cnt, root;
    void push_up(int rt) {
        tree[rt].size = tree[tree[rt].ch[L]].size + tree[tree[rt].ch[R]].size + 1;
    }
    void push_down(int rt) {
        if(tree[rt].rv) {
            tree[tree[rt].ch[L]].rv ^= 1;
            tree[tree[rt].ch[R]].rv ^= 1;
            swap(tree[rt].ch[L], tree[rt].ch[R]);
            tree[rt].rv = 0;
        }
    }
                        /*    y        x  */
                        /*   / \      / \ */
    /*保证x的权值小于y 那么有 x   o 或 o   y*/
    int merge(int x, int y) { 
        if(!x || !y) return x + y;
        push_down(x), push_down(y);
        if(tree[x].key > tree[y].key) {tree[x].ch[R] = merge(tree[x].ch[R], y), push_up(x);return x;}
        else {tree[y].ch[L] = merge(x, tree[y].ch[L]), push_up(y);return y;}
    }
    /*  x     y       x    Y     Y    x  */
/*节点 / \   / \  -> / \     ->      / \ */
    /*Y   o o   o   y   o           y   o*/
    /*  3     2       3    1     1    3  */
/*权值 / \   / \  -> / \     ->      / \ */
    /*1   o o   o   2   o           2   o*/
    void split(int & x, int k, int & y) {
        push_down(x);
        if(tree[x].size == k) {y = 0; return ;}
        if(tree[tree[x].ch[L]].size >= k) {
            split(tree[x].ch[L], k, y);
            swap(tree[x].ch[L], y);        
            swap(x, y);                    
            push_up(y);                
        } else {						   
            split(tree[x].ch[R], k - tree[tree[x].ch[L]].size - 1, y);
            push_up(x);
        }
    }
    void insert(int val) {
        tree[++cnt].key = rand() * rand();
        tree[cnt].num = val, tree[cnt].size = 1;
        root = merge(root, cnt);
    }
    void rev(int l, int r) {
        int rt1, rt2;
        split(root, r, rt1), split(root, l - 1, rt2);
        tree[rt2].rv ^= 1;
        root = merge(root, rt2);
        root = merge(root, rt1);
    }
    void out(int rt) {
        push_down(rt);
        if(tree[rt].ch[L]) out(tree[rt].ch[L]);
        printf("%d ", tree[rt].num);
        if(tree[rt].ch[R]) out(tree[rt].ch[R]);
    }
}

int main() {
    using namespace Treap;
    srand(time(0));
    scanf("%d%d", &n, &m);
    for(register int i = 1; i <= n; ++i) insert(i);
    for(register int i = 1; i <= m; ++i) {
        scanf("%d%d", &a, &b);
        rev(a, b);
    }
    out(root);
    return 0;
}

 ------+------+------+---update:2018.6.3---+------+------+------

用指针写了splay,没有卡过数组什么鬼

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1.5e5 + 5;

int a[maxn];

namespace Splay {
	#define L 0
	#define R 1
	typedef struct node* ptr;
	struct node {
		int size, num, rv;
		ptr fa, ch[2];
		void init(int x, ptr nul) {
			ch[L] = ch[R] = nul;
			size = 1, num = x;
		}
		void push_up() {
			size = ch[L] -> size + ch[R] -> size + 1;
		}
	} tree[maxn];
	ptr root; int cnt;
	void push_up(node * x) {
		if(x == NULL) return;
		x -> push_up();
	}
	void push_down(ptr x) {
		if(x != NULL && x -> rv) {
			swap(x -> ch[L], x -> ch[R]);
			x -> ch[L] -> rv ^= 1;
			x -> ch[R] -> rv ^= 1;
			x -> rv = 0;
		}
	}
	ptr build(int * a, int l, int r, ptr fa) {
		ptr now = &tree[++cnt];
		now -> fa = fa;
		if(l == r) {
			now -> init(a[l], &tree[0]);
			return now;
		}
		int mid = l + r >> 1;
		now -> init(a[mid], &tree[0]);
		if(l < mid) now -> ch[L] = build(a, l, mid - 1, now);
		if(mid < r) now -> ch[R] = build(a, mid + 1, r, now);
		push_up(now);
	}
	void rotate(ptr x) {
		ptr p = x -> fa, a = p -> fa;
		int r = p -> ch[R] == x, l = r ^ 1;
		if(a != NULL) a -> ch[a -> ch[R] == p] = x;
		p -> ch[r] = x -> ch[l], x -> ch[l] = p;
		p -> ch[r] -> fa = p, p -> fa = x, x -> fa = a;
		push_up(p), push_up(x);
	}
	void splay(ptr x, ptr y) {
		ptr des = y -> fa;
		while(x -> fa != des) {
			node *p = x -> fa, *a = p -> fa;
			push_down(a), push_down(p), push_down(x);
			if(a != des) {
				if((p -> ch[R] == x) ^ (a -> ch[R] == p))
				rotate(x); else rotate(p);
			}
			rotate(x);
		}
		if(root == y) root = x;
	}
	ptr Qkr(int k) {
		ptr now = root;
		int siz = 0;
		while(1) {
			push_down(now);
			siz = now -> ch[L] -> size;
			if(siz + 1 < k) now = now -> ch[R], k -= siz + 1;
			else if(siz + 1 > k) now = now -> ch[L];
			else return now;
		}
	}
	void Rev(int l, int r) {
		ptr LN = Qkr(l), RN = Qkr(r + 2);
		splay(LN, root);
		splay(RN, root -> ch[R]);
		RN -> ch[L] -> rv ^= 1;
	}
	void Out(ptr x) {
		push_down(x);
		if(x -> ch[L] != &tree[0]) Out(x -> ch[L]);
		if(x -> num <= maxn && x -> num > 0)
			printf("%d ", x -> num);
		if(x -> ch[R] != &tree[0]) Out(x -> ch[R]);
	}
}

int n, m, l, r;
int main() {
	scanf("%d%d", &n, &m);
	for(register int i = 1; i <= n; ++i)
		a[i] = i;
	a[0] = -0x7fffffff;
	a[n + 1] = 0x7fffffff;
	Splay::root = Splay::build(a, 0, n + 1, NULL);
	for(register int i = 1; i <= m; ++i) {
		scanf("%d%d", &l, &r);
		Splay::Rev(l, r);
	}
	Splay::Out(Splay::root);
	return 0;
}

 

上一篇: BZOJ3676: [Apio2014]回文串

下一篇: 洛谷P3796 【模板】AC自动机(加强版)

495 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航