文藝平衡樹:FHQ-Treap 實現區間操作

之前學了FHQ-Treap 但是很生疏,今天就完全自己碼一發,熟悉熟悉,調調bug,,熟悉一下代碼裏面的各種細節問題。

因爲FHQ-Treap 要實現區間操作,是不能按值分裂的,需要按節點大小分裂,這樣我們只需要將節點大小爲[l,r]區間的這顆樹分解出來,然後進行修改即可。

文藝平衡樹,是要顛倒 q 次的詢問區間,最後輸出整個區間,試想一下,如果樸素寫法絕對複雜度爆炸,所以用 FHQ-Treap 的操作就很 loglog 了,雖然常數有點大,但不是問題。

講一下思路(菜雞的小思路):
分裂出包含 [l,r] 區間的平衡樹,對這顆樹打上標記,交換左右兒子節點即可,然後合併回整顆平衡樹,在合併的時候,下傳標記即可。

傳送門:文藝平衡樹

參考代碼:

#include <cstdio>
#include <algorithm>
#include <vector>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <cstring>
#include <string>
#include <cstdlib>
#include <cmath>
using namespace std;
typedef long long ll;
const int inf = 1 << 30;
const int maxn = 2e5 + 5;
const int N = 1e3 + 5;
const int base = 131;
struct node
{
    int ls, rs, sizx, w, lazy, key;
} tr[maxn];
int su = 1, cnt, rt;
int rand()
{
    su = (su * base) % 1000007;
    return su;
}
int newnode(int w)
{
    tr[++cnt].w = w, tr[cnt].key = rand();
    tr[cnt].sizx = 1, tr[cnt].lazy = 0;
    return cnt;
}
void pushup(int now)
{
    tr[now].sizx = tr[tr[now].ls].sizx + tr[tr[now].rs].sizx + 1;
}
void pushdown(int now)
{
    if (tr[now].lazy)
    {
        swap(tr[now].ls, tr[now].rs);
        tr[tr[now].ls].lazy ^= 1, tr[tr[now].rs].lazy ^= 1;
        tr[now].lazy = 0;
    }
}
void split(int now, int mid, int &x, int &y)
{
    if (!now)
        x = y = 0;
    else
    {
        pushdown(now);
        if (mid <= tr[tr[now].ls].sizx)
        {
            y = now, split(tr[now].ls, mid, x, tr[now].ls);
        }
        else
        {
            x = now, split(tr[now].rs, mid - tr[tr[now].ls].sizx - 1, tr[now].rs, y);
        }
        pushup(now);
    }
}
int merge(int x, int y)
{
    if (!x || !y)
        return x + y;
    else
    {
        if (tr[x].key > tr[y].key)
        {
            pushdown(x);
            tr[x].rs = merge(tr[x].rs, y);
            pushup(x);
            return x;
        }
        else
        {
            pushdown(y);
            tr[y].ls = merge(x, tr[y].ls);
            pushup(y);
            return y;
        }
    }
}
void reverse(int l, int r)
{
    int x, y, z;
    split(rt, l - 1, x, y);
    split(y, r - l + 1, y, z);
    tr[y].lazy ^= 1;
    rt = merge(x, merge(y, z));
}
void dfs(int now)
{
    if (!now)
        return;
    pushdown(now);
    dfs(tr[now].ls);
    cout << tr[now].w << ' ';
    dfs(tr[now].rs);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, q;
    cin >> n >> q;
    for (int i = 1; i <= n; i++)
        rt = merge(rt, newnode(i));
    while (q--)
    {
        int ql, qr;
        cin >> ql >> qr;
        reverse(ql, qr);
    }
    dfs(rt);
}
// PAYPALISHIRING"
// 7
// 1,8,6,2,5,4,8,3,7
// 5 3
// 1 3
// 1 3
// 1 4
// 4 3 2 1 5
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章