FHQ-Treap学习笔记 / 洛谷 P2042 / bzoj1500 【FHQ-Treap】【栈】

11 篇文章 0 订阅
8 篇文章 0 订阅

FHQ-Treap学习笔记

FHQ-Treap可以解决的问题:splay能解决的除了LCT以外的所有问题。

FHQ-Treap有两种操作,分别是merge和split。

FHQ-Treap和普通的Treap一样,都有两个值key和val。

mt19937 gen(chrono::system_clock::now().time_since_epoch().count());
uniform_int_distribution <int> rnd;
void initmtrft(int mvfzgh = 100000000) {
  uniform_int_distribution <int> rndtmpfimt(1, mvfzgh);
  rnd = rndtmpfimt;
}

int grfntrft() {
  return rnd(gen);
}

struct Node {
  int val, key, size;
  int l, r;
  Node () {
    val = 0;
    size = l = r = 0;
    key = grfntrft();
  }
}

merge操作:合并两棵FHQ-Treap。类似于启发式合并,在两棵Treap中找到根节点key值最大的根节点,然后继续递归处理即可。

void merge(int p1, int p2) {
  if (!p1)
    return p2;
  if (!p2)
    return p1;
  if (z[p1].key > z[p2].key) {
    z[p1].r = merge(z[p1].r, p2);
    update(p1);
    return p1;
  } else {
    z[p2].l = merge(p1, z[p2].l);
    update(p2);
    return p2;
  }
}

split操作:在一个FHQ-Treap中拆出value最小的 k k k 个节点变成两棵FHQ-Treap。

实际上就是找根操作,如果当前左儿子大小 ≤ k \le k k 那么根在左儿子上,如果 = k + 1 = k+1 =k+1 那么在根节点上(不需特判),如果 > k + 1 >k+1 >k+1 那么根在右儿子上且 k k k 要去掉左儿子和根的值。

pair <int, int> split(int p, int k) {
  if (p == 0)
    return make_pair(0, 0);
  if (z[z[p].l].size + 1 <= k) {
    auto res = split(z[p].r, k - z[z[p].l].size - 1);
    z[p].r = res.first;
    update(p);
    return make_pair(p, res.second);
  } else {
    auto res = split(z[p].l, k);
    z[p].l = res.second;
    update(p);
    return make_pair(res.first, p);
  }
}

新建一个空的节点(截自 P2042):

int new_node(int value) {
    int p = stk.top();
    stk.pop();
    z[p].key = rand();
    z[p].l = z[p].r = 0;
    z[p].size = 1;
    z[p].l_max = z[p].r_max = max(0LL, value);
    z[p].mx = value;
    z[p].value = z[p].sum = value;
    z[p].cover = z[p].rever = 0;
    z[p].lazy = 0;
    return p;
}

例题 洛谷 P2042:

// 代码进行多个优化 请忽视奇怪的Tab长度
#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e6 + 233;

int n, m;

stack <int> stk;

struct Node {
    int key, l, r, value, size, l_max, r_max, sum, cover, rever, mx, lazy;
    Node () {
        key = l = r = value = size = l_max = r_max = sum = cover = rever = mx = lazy = 0;
    }
} z[N];

int rt, a[N];

void init_stk() {
    for (int i = 1; i < N - 3; i ++)
        stk.push(i);
}

int new_node(int value) {
    int p = stk.top();
    stk.pop();
    z[p].key = rand();
    z[p].l = z[p].r = 0;
    z[p].size = 1;
    z[p].l_max = z[p].r_max = max(0LL, value);
    z[p].mx = value; // 题目要求至少选一个
    z[p].value = z[p].sum = value;
    // * cover 是推平标记
    // * rever 是翻转标记
    z[p].cover = z[p].rever = 0;
    z[p].lazy = 0;
    return p;
}

void update(int p) {
    z[p].size = z[z[p].l].size + z[z[p].r].size + 1;
    z[p].sum = z[z[p].l].sum + z[z[p].r].sum + z[p].value;
    z[p].l_max = max(0LL, max(z[z[p].l].l_max, z[z[p].r].l_max + z[z[p].l].sum + z[p].value));
    z[p].r_max = max(0LL, max(z[z[p].r].r_max, z[z[p].l].r_max + z[z[p].r].sum + z[p].value));
    z[p].mx = max(z[p].value, z[z[p].l].r_max + z[z[p].r].l_max + z[p].value);
    if (z[p].l) z[p].mx = max(z[p].mx, z[z[p].l].mx);
    if (z[p].r) z[p].mx = max(z[p].mx, z[z[p].r].mx);
}

void reverse(int p) {
    swap (z[p].l_max, z[p].r_max);
    swap (z[p].l, z[p].r);
    z[p].rever ^= 1;
}

void modify(int p, int value) {
    z[p].value = z[p].cover = value;
    z[p].sum = z[p].size * value;
    z[p].l_max = z[p].r_max = max(0LL, z[p].sum);
    z[p].mx = max(value, z[p].sum);
    z[p].lazy = 1;
}

void pushdown(int p) {
    if (z[p].rever) {
        if (z[p].l)
            reverse(z[p].l);
        if (z[p].r)
            reverse(z[p].r);
        z[p].rever = 0;
    }
    if (z[p].lazy) {
        if (z[p].l)
            modify(z[p].l, z[p].cover);
        if (z[p].r)
            modify(z[p].r, z[p].cover);
        z[p].lazy = 0;
    }
}

pair <int, int> split(int p, int k) {
    if (!p) return make_pair(0, 0);
    pushdown(p);
    if (z[z[p].l].size >= k) {
        auto res = split(z[p].l, k);
        z[p].l = res.second;
        update(p);
        return make_pair(res.first, p);
    } else {
        auto res = split(z[p].r, k - z[z[p].l].size - 1);
        z[p].r = res.first;
        update(p);
        return make_pair(p, res.second);
    }
}

int merge(int a, int b) {
    if (!a) return b;
    if (!b) return a;
    if (z[a].key < z[b].key) {
        pushdown(a);
        z[a].r = merge(z[a].r, b);
        update(a);
        return a;
    } else {
        pushdown(b);
        z[b].l = merge(a, z[b].l);
        update(b);
        return b;
    }
}

int build(int l, int r) {
    if (l == r)
        return new_node(a[l]);
    int mid = l + r >> 1;
    int res1 = build(l, mid), res2 = build(mid + 1, r);
    return merge(res1, res2);
}

void remove(int p) {
    stk.push(p);
    if (z[p].l)
        remove(z[p].l);
    if (z[p].r)
        remove(z[p].r);
}

void insert(int pos, int tot) {
    auto res = split(rt, pos);
    rt = merge(merge(res.first, build(1, tot)), res.second);
}

void remove(int pos, int tot) {
    auto res = split(rt, pos - 1);
    auto res2 = split(res.second, tot);
    remove(res2.first);
    rt = merge(res.first, res2.second);
}

void reverse(int pos, int tot) {
    auto res = split(rt, pos - 1);
    auto res2 = split(res.second, tot);
    reverse(res2.first);
    rt = merge(res.first, merge(res2.first, res2.second));
}

void getsum(int pos, int tot) {
    auto res = split(rt, pos - 1);
    auto res2 = split(res.second, tot);
    cout << z[res2.first].sum << '\n';
    rt = merge(res.first, merge(res2.first, res2.second));
}

void modify(int pos, int tot, int value) {
    auto res = split(rt, pos - 1);
    auto res2 = split(res.second, tot);
    modify(res2.first, value);
    rt = merge(res.first, merge(res2.first, res2.second));
}

void getmax() {
    cout << z[rt].mx << '\n';
}

signed main() {
    srand(time(0));
    init_stk();
    cin >> n >> m;
    for (int i = 1; i <= n; i ++)
        cin >> a[i];
    rt = build(1, n);
    while (m --) {
        string s;
        cin >> s;
        if (s == "INSERT") {
            int pos, tot;
            cin >> pos >> tot;
            for (int i = 1; i <= tot; i ++)
                cin >> a[i];
            insert(pos, tot);
        } else if (s == "DELETE") {
            int pos, tot;
            cin >> pos >> tot;
            remove(pos, tot);
        } else if (s == "REVERSE") {
            int pos, tot;
            cin >> pos >> tot;
            reverse(pos, tot);
        } else if (s == "GET-SUM") {
            int pos, tot;
            cin >> pos >> tot;
            getsum(pos, tot);
        } else if (s == "MAX-SUM") {
            getmax();
        } else {
            int pos, tot, value;
            cin >> pos >> tot >> value;
            modify(pos, tot, value);
        }
    }
    return 0;
}
注:除例题代码外其他的代码均没有编译运行,有可能会出现错误。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值