【bzoj3223】Tyvj 1729 文艺平衡树
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
Input
第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2……n-1,n) m表示翻转操作次数 接下来m行每行两个数[l,r] 数据保证 1<=l<=r<=n
Output
输出一行n个数字,表示原始序列经过m次变换后的结果
Sample Input
5 3
1 3
1 3
1 4
Sample Output
4 3 2 1 5
HINT
N,M<=100000
思路
区间翻转问题
翻转区间->交换BST的左右子树(逐层交换,正确性请自行验证),区间标记降低翻转次数
寻找要操作的区间[l,r]:将当前排名(size)为l的节点(节点l-1)转到根,将当前排名为r+2的节点(节点r+1)转到根的右子树的根节点,则根的右子树的根节点的左子树为所求区间,直接标记该区间就可以了。(类似线段树区间修改)
splay操作维护一棵较优的树,三种方式进行旋转操作。
注意
1.标记是在每一次访问到一个新的节点是就要pushdown的(改变树的结构会破坏标记区间,所以先一步下传标记)
2.区分一个节点的排名和这个节点的值:这个节点的排名是它是当前数组中的第几个,用左儿子的size+1表示;这个节点的值是题目中输入的数字,在本题中是1~n
3.增加数字为0和n+1的两个哨兵节点,因为如果对区间1~x或x~n操作,用到前后的节点就需要0和n+1。
4.有些读者会疑惑,难道交换左右子树不会破坏BST的性质吗?这就是容易混淆的一点,我们的区间操作是根据下标翻转的,用数组实现时下标就是数组地址,子树交换时,只是存储内容的改变,下标位置(树的形状)只会在旋转时改变,保证BST性质。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;