zoukankan      html  css  js  c++  java
  • [bzoj3223]文艺平衡树——splay

    题意

    你应当编写一个数据结构,支持以下操作:

    1. 反转一个区间

    题解

    我们把在数组中的位置当作权值,这样原序列就在这种权值意义下有序,我们考虑使用splay维护。
    对于操作rev[l,r],我们首先把l-1 splay 到根,再把r+1 splay 到根的右子树的根,那么根的右子树的左子树就是区间[l,r]。
    显然,这样会用到l-1和r+1。我们考虑添加两个哨兵节点,分别是1和n+2,[1,n]的值再分别加一就好了。
    另外,为了防止过多的swap,我们延续线段树中的做法, 打一个lazy标记。与线段树不同的是,由于splay的拓扑结构经常会变化,所以每访问到一个节点,都要下传lazy标记。
    注意build的写法。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int n, m, sz, rt;
    #ifdef DEBUG
    const int maxn = 100;
    #else
    const int maxn = 100005;
    #endif
    int fa[maxn], c[maxn][2], id[maxn];
    int size[maxn];
    bool rev[maxn];
    void pushup(int k) {
      int l = c[k][0], r = c[k][1];
      size[k] = size[l] + size[r] + 1;
    }
    void pushdown(int k) {
      int &l = c[k][0], &r = c[k][1];
      if (rev[k]) {
        swap(l, r);
        rev[l] ^= 1;
        rev[r] ^= 1;
        rev[k] = 0;
      }
    }
    void zig(int x, int &k) {         // do one zig
      int y = fa[x], z = fa[y], l, r; // y:father z:grandfather
      if (c[y][0] == x) {             // zig
        l = 0;
      } else
        l = 1; // zag
      r = l ^ 1;
      if (y == k)
        k = x; // single zig
      else {   // update grandfather
        if (c[z][0] == y)
          c[z][0] = x; // zig-zig
        else
          c[z][1] = x;
      }
      fa[x] = z;
      fa[y] = x;
      fa[c[x][r]] = y;
      c[y][l] = c[x][r];
      c[x][r] = y;
      pushup(y);
      pushup(x);
    }
    void splay(int x, int &k) {
      while (x != k) {
        int y = fa[x], z = fa[y];
        if (y != k) {
          if (c[y][0] == x ^ c[z][0] == y) // diff:zig-zag or zag-zig
            zig(x, k);
          else // same:zig-zig or zag-zag
            zig(y, k);
        }
        zig(x, k);
      }
    }
    int find(int k, int rank) {
      pushdown(k);
      int l = c[k][0], r = c[k][1];
      if (size[l] + 1 == rank)
        return k;
      else if (size[l] >= rank)
        return find(l, rank);
      else
        return find(r, rank - size[l] - 1);
    }
    
    void rever(int l, int r) {
      int x = find(rt, l), y = find(rt, r + 2);
      splay(x, rt);
      splay(y, c[x][1]);
      int z = c[y][0];
      rev[z] ^= 1;
    }
    void build(int l, int r, int f) { // f:last node
      if (l > r)
        return;
      int now = id[l], last = id[f];
      if (l == r) {
        fa[now] = last;
        size[now] = 1;
        if (l < f)
          c[last][0] = now;
        else
          c[last][1] = now;
        return;
      }
      int mid = (l + r) >> 1;
      now = id[mid];
      build(l, mid - 1, mid);
      build(mid + 1, r, mid);
      fa[now] = last;
      pushup(mid);
      if (mid < f) {
        c[last][0] = now;
      } else
        c[last][1] = now;
      return;
    }
    
    int main() {
    #ifdef DEBUG
      freopen("input", "r", stdin);
    #endif
      scanf("%d %d", &n, &m);
      for (int i = 1; i <= n + 2; i++)
        id[i] = ++sz;
      build(1, n + 2, 0);
      rt = (n + 3) >> 1;
      for (int i = 1; i <= m; i++) {
        int l, r;
        scanf("%d %d", &l, &r);
        rever(l, r);
      }
      for (int i = 2; i <= n + 1; i++) {
        printf("%d ", find(rt, i) - 1);
      }
      return 0;
    }
    
  • 相关阅读:
    从Go语言编码角度解释实现简易区块链——打造公链
    CSAPP:位操作实现基本运算
    虚拟机Ubuntu系统无法连接网络解决方案
    CSAPP:逆向工程【二进制炸弹】
    分析一套源代码的代码规范和风格并讨论如何改进优化代码
    【Recorder.js+百度语音识别】全栈方案技术细节
    webpack4.0各个击破(5)—— Module篇
    webpack4.0各个击破(4)—— Javascript & splitChunk
    webpack4.0各个击破(3)—— Assets篇
    javascript基础修炼(4)——UMD规范的代码推演
  • 原文地址:https://www.cnblogs.com/gengchen/p/6472355.html
Copyright © 2011-2022 走看看