LibreOJ104 - 普通平衡树 (平衡树)

这是一道模板题。

您需要写一种数据结构(可参考题目标题),来维护一个序列,其中需要提供以下操作:

翻转一个区间,例如原有序序列是 5 4 3 2 1,翻转区间是 [2,4] 的话,结果是 5 2 3 4 1。

思路
这题体现了无旋treap的区间操作。

注意不能按照关键值来排序,要按照当前结点的位置来排序。更新过程中维护好当前结点之前有多少结点(cnt)。

这样treap就可以把区间分裂出来。分裂后再合并,会改变treap的结构,却不改变treap的中序遍历。
所以如果有一个有序序列,将它们插入到treap中,分裂的treap的中序遍历就是这个有序序列某个子序列。所以可以把这个treap看成这个子序列,对其进行各种操作。

翻转区间就是把区间[l,r]的treap分裂出来,然后交换每个结点的左右子结点。

为什么可以这样做呢?因为中序遍历的顺序是: 左结点,此结点,右结点。这样就可以按顺序(比如从小到大,看你结点关系怎么组织)输出。
如果你swap子树的每个结点的左右结点,相当于以 右结点,此结点,左结点的顺序来遍历,结果就是顺序反过来(逆序),相当于翻转。可以使用懒惰标记(类似线段树),来减少不必要的翻转。

而且交换每个结点的左右子结点不会改变堆的性质,使得翻转后还是个合法的treap。

Copy

`#include

include

include

include

include

include

include

include

include

include

include

include

include

include

define endl 'n'

define IOS std::ios::sync_with_stdio(0);

define FILE freopen("..//data_generator//in.txt","r",stdin),freopen("res.txt","w",stdout)

define FI freopen("..//data_generator//in.txt","r",stdin)

define FO freopen("res.txt","w",stdout)

define pb cpush_back

define mp make_pair

define seteps(N) fixed << setprecision(N)

typedef long long ll;
using namespace std;
/-----------------------------------------------------------------/

define INF 0x3f3f3f3f

const int N = 1e6 + 10;
const int M = 1e9 + 7;
const double eps = 1e-8;

int pos[N];
int lc[N], rc[N];
int val[N];
int cnt[N];
int lazy[N];
int si;

typedef pair PII;

void pushdown(int rt) {

if(lazy[rt]) {
    swap(lc[rt], rc[rt]);
    lazy[lc[rt]]++;
    lazy[rc[rt]]++;
    lazy[lc[rt]] %= 2;
    lazy[rc[rt]] %= 2;
    lazy[rt] = 0;
}

}

PII split(int rt, int key) {

if(!key || !rt) {
    return mp(0, rt);
}
pushdown(rt);
if(key < cnt[lc[rt]] + 1) {
    PII o = split(lc[rt], key);
    lc[rt] = o.second;
    cnt[rt] = cnt[lc[rt]] + cnt[rc[rt]] + 1;
    return mp(o.first, rt);
} else {
    PII o = split(rc[rt], key - cnt[lc[rt]] - 1);
    rc[rt] = o.first;
    cnt[rt] = cnt[lc[rt]] + cnt[rc[rt]] + 1;
    return mp(rt, o.second);
}

}

int merge(int lrt, int rrt) {

if(!lrt) return rrt;
if(!rrt) return lrt;
pushdown(lrt);
pushdown(rrt);
if(pos[lrt] > pos[rrt]) {
    rc[lrt] = merge(rc[lrt], rrt);
    cnt[lrt] = cnt[lc[lrt]] + cnt[rc[lrt]] + 1;
    return lrt;
} else {
    lc[rrt] = merge(lrt, lc[rrt]);
    cnt[rrt] = cnt[lc[rrt]] + cnt[rc[rrt]] + 1;
    return rrt;
}

}

int insert(int v, int rt) {

++si;
val[si] = v;
pos[si] = rand();
cnt[si] = 1;
return merge(rt, si);

}

void print(int rt) {

if(!rt) return ;
pushdown(rt);
print(lc[rt]);
cout << val[rt] << " "; 
print(rc[rt]);

}

int reverse(int l, int r, int rt) {

int tar;
PII o1 = split(rt, r);
tar = o1.first;
PII o2 = o1;
if(l > 1) {
    o2 = split(tar, l - 1);
    tar = o2.second;
}
lazy[tar] = 1;
if(l > 1) return merge(merge(o2.first, o2.second), o1.second);
return merge(o1.first, o1.second);

}

int main() {

IOS;
//FO;
int n, m;
cin >> n >> m;
int rt = 0;
for(int i = 1; i <= n; i++) {
    rt = insert(i, rt);
}
while(m--) {
    int l, r;
    cin >> l >> r;
    rt = reverse(l, r, rt);
}
print(rt);

}`

你可能感兴趣的:(LibreOJ104 - 普通平衡树 (平衡树))