BZOJ 3217: ALOEXT

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3217: ALOEXT相关的知识,希望对你有一定的参考价值。

Description

 taorunz平时最喜欢的东西就是可移动存储器了……只要看到别人的可移动存储器,他总是用尽一切办法把它里面的东西弄到手。

突然有一天,taorunz来到了一个密室,里面放着一排可移动存储器,存储器里有非常珍贵的OI资料……不过比较特殊的是,每个存储器上都写着一个非负整数。taorunz很高兴,要把所有的存储器都拿走(taorunz的智商高达500,他一旦弄走了这里的所有存储器,在不久到来的AHOI和NOI中……你懂的)。不过这时有一个声音传来:“你只能拿走这里的一个存储器,而且还不能直接拿,你需要指定一段区间[l, r],满足l<r,然后在第l个和第r个存储器之间选一个拿走,你能获得的知识增加量等于区间[l, r]中所有存储器上写的整数的次大值与你拿走的这个存储器上写的整数作按位异或运算的结果。”

问题是,这里的可移动存储器数量太多,而且,它们还在不断地发生变化,有时候天上会掉下来一个新的存储器,并插入到这一排存储器中,有时候某个存储器会不明原因消失,有时候某个存储器上写的整数变化了。taorunz虽然智商很高,但也无法应对如此快的变化,他指定了许多段区间,让你帮他找出如果在这个区间中拿走存储器,他能获得的最多的知识是多少。

Input

第一行两个整数N、M,表示一开始的存储器数和后面发生的事件数。

第二行N个非负整数,表示一开始从左到右每个存储器上写的数字。注意,存储器从0开始编号,也就是最左边的存储器是第0个。

接下来M行,每行描述一个事件,有4种可能的事件。

(1)I x y:表示天上掉下来一个写着数字y的存储器,并插入到原来的第x个存储器之前,如果x等于原来存储器的个数,则插入到末尾;

(2)D x:表示第x个存储器消失;

(3)C x y:表示第x个存储器上写的数字变为y;

(4)F l r:表示taorunz指定区间[l, r],让你告诉他最多能获得多少知识。

注意,本题强制在线,也就是事件中出现的所有数字都进行了加密,数字s表示的真实值是

对于I、D、C事件中的x及F事件中的l、r:(s+last_ans) mod n0;

对于I、C事件中的y:(s+last_ans) mod 1048576。

其中n0为目前存储器个数,last_ans为上一个F事件的结果,如果前面尚未发生F事件,则last_ans=0。

Output 

对于每个F事件,输出结果。 

Sample Input

5 10
2 6 3 8 7
F 1 4
I 2 1048565
I 0 1048566
D 3
F 3 0
I 3 1048569
D 5
C 1 1048570
F 1 2
F 2 1

Sample Output

15
7
4
7

HINT

1<=N, M<=100000。所有F事件满足l<r。
本题共有5组数据,除1组为随机数据外,其它数据均为人工构造。

 

分块 / 替罪羊树

然而替罪羊树的节点数是O(N logN),Trie树是O(N logN * 20),空间很卡,要写回收.

分块可快了,虐飞替罪羊树。

 

#include <cstdio>
#include <iostream>
#define ri register int
using namespace std;

const int M = 3000;

inline void Upd(int &Max1, int &Max2, int x) {
  if (x > Max1) {Max2 = Max1; Max1 = x;}
  else Max2 = max(Max2, x);
}

int lastans = 0, n0 = 0, b = 0;

struct Node {
  Node *ch[2];
  int key;
  Node() {key = 0; ch[0] = ch[1] = NULL;}
} pool[5000000], *S = pool;

inline void Trie_Add(Node *rt, int x, int val) {
  for (ri i = 19; (~ i); i --) {
    rt -> key += val;
    if (rt -> ch[(x >> i) & 1] == NULL) rt -> ch[(x >> i) & 1] = S ++;
    rt = rt -> ch[(x >> i) & 1];
  }
  rt -> key += val;
}

inline int Trie_Query(Node *rt, int x) {
  if (rt -> key == 0) return 0;
  ri res = 0;
  for (ri i = 19; (~ i); i --) {
    if (rt -> ch[!((x >> i) & 1)] != NULL && rt -> ch[!((x >> i) & 1)] -> key) {
      rt = rt -> ch[!((x >> i) & 1)];
      res ^= 1 << i;
    }
    else rt = rt -> ch[(x >> i) & 1];
  }
  return res;
}

struct Block {
  int a[M + 10], Max1, Max2, tot, nxt;
  Node *Trie;
  
  Block() {Max1 = Max2 = -1; nxt = tot = 0;}
  
  inline void update() {
    Max1 = Max2 = 0;
    for (ri i = 1; i <= tot; i ++) Upd(Max1, Max2, a[i]);
  }
  inline void Modify(int p, int v) {
    Trie_Add(Trie, a[p], -1);
    Trie_Add(Trie, v, 1);
    a[p] = v; Max1 = Max2 = -1;
  }
  inline void Insert(int p, int v) {
    n0 ++;
    for (ri i = ++ tot; i > p; i --) a[i] = a[i - 1];
    a[p] = v;
    Trie_Add(Trie, v, 1);
    if (Max1 != -1) Upd(Max1, Max2, v);
  }
  inline void Delete(int p) {
    n0 --;
    Trie_Add(Trie, a[p], -1);
    for (ri i = p; i < tot; i ++) a[i] = a[i + 1];
    tot --;
    Max1 = Max2 = -1;
  }
} B[150];

inline void work1() {
  int x, y;
  scanf("%d%d", &x, &y);
  x = (x + lastans) % n0 + 1;
  y = (y + lastans) % 1048576;
  for (int i = 1; i; i = B[i].nxt) {
    if (B[i].tot + 1 >= x) {
      B[i].Insert(x, y);
      if (B[i].tot == M) {
        B[++ b].nxt = B[i].nxt;
        B[b].Trie = S ++;
        B[i].nxt = b;
        Node *II = B[i].Trie, *BB = B[b].Trie;
        for (ri j = 1501; j <= 3000; j ++) {
          B[b].a[j - 1500] = B[i].a[j];
          Trie_Add(II, B[i].a[j], -1);
          Trie_Add(BB, B[i].a[j], 1);
        }
        B[i].Max1 = -1;
        B[b].tot = B[i].tot = 1500;
      }
      return;
    }
    x -= B[i].tot;
  }
}

inline void work2() {
  int x;
  scanf("%d", &x);
  x = (x + lastans) % n0 + 1;
  for (int i = 1; i; i = B[i].nxt) {
    if (B[i].tot >= x) {B[i].Delete(x); return;}
    x -= B[i].tot;
  }
}

inline void work3() {
  int x, y;
  scanf("%d%d", &x, &y);
  x = (x + lastans) % n0 + 1;
  y = (y + lastans) % 1048576;
  for (int i = 1; i; i = B[i].nxt) {
    if (B[i].tot >= x) {B[i].Modify(x, y); return;}
    x -= B[i].tot;
  }
}

inline void work4() {
  int l, r, Max1 = 0, Max2 = 0, R, p, q;
  scanf("%d%d", &l, &r);
  l = (l + lastans) % n0 + 1;
  r = (r + lastans) % n0 + 1;
  if (l > r) swap(l, r);
  p = l; q = r;
  for (int i = 1; i; i = B[i].nxt) {
    if (B[i].tot >= l && l > 0) {
      R = min(B[i].tot, r);
      for (ri j = l; j <= R; j ++) Upd(Max1, Max2, B[i].a[j]);
      if (R == r) break;
    }
    if (B[i].tot >= r) {
      for (ri j = 1; j <= r; j ++) Upd(Max1, Max2, B[i].a[j]);
      break;
    }
    if (l <= 0) {
      if (B[i].Max1 == -1) B[i].update();
      Upd(Max1, Max2, B[i].Max1);
      Upd(Max1, Max2, B[i].Max2);
    }
    l -= B[i].tot;
    r -= B[i].tot;
  }
  l = p; r = q;
  lastans = 0;
  for (int i = 1; i && r > 0; i = B[i].nxt) {
    if (B[i].tot >= l && l > 0) {
      R = min(B[i].tot, r);
      for (ri j = l; j <= R; j ++) lastans = max(lastans, Max2 ^ B[i].a[j]);
      if (R == r) break;
    }
    else if (B[i].tot >= r) {
      for (ri j = 1; j <= r; j ++) lastans = max(lastans, Max2 ^ B[i].a[j]);
      break;
    }
    else if (l <= 0) {
      lastans = max(lastans, Trie_Query(B[i].Trie, Max2));
    }
    l -= B[i].tot;
    r -= B[i].tot;
  }
  printf("%d\n", lastans);
}

int main() {
  int n, m;
  char s[10];
  scanf("%d%d", &n, &m);
  int en = 1, x;
  for (ri i = 1; i <= n; i ++) {
    if (i == en) {
      B[b].nxt = b + 1;
      b ++; en += M >> 1;
      B[b].Trie = S ++;
    }
    scanf("%d", &x);
    B[b].Insert(B[b].tot + 1, x);
  }
  if (!b) b = 1, B[b].Trie = S ++;
  while (m --) {
    scanf("%s", s);
    if (s[0] == ‘I‘) work1();
    else if (s[0] == ‘D‘) work2();
    else if (s[0] == ‘C‘) work3();
    else work4();
  }
  return 0;
}

  

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#define ri register int
#define mid ((L + R) >> 1)
#define fi first
#define se second
#define mp make_pair
#define alp 0.8
#define clr(x) O[x].key = O[x].ch[0] = O[x].ch[1] = 0
using namespace std;

typedef long long LL;
typedef pair <int, int> pii;
const int N = 1e5 + 5;
const int M = 33000000;

struct node {
  int ch[2], key;
} O[M];
queue <int> Q;
int sz = 0;

inline void Discard(int x) {
  if (!x) return;
  Q.push(x);
  Discard(O[x].ch[0]);
  Discard(O[x].ch[1]);
}

inline void Insert(int rt, int x, int v) {
  int r;
  for (ri i = 19; (~ i); i --) {
    O[rt].key += v;
    if (!O[rt].ch[(x >> i) & 1]) {
      if (Q.size()) {r = Q.front(); Q.pop(); clr(r);}
      else r = ++ sz;
      O[rt].ch[(x >> i) & 1] = r;
    }
    if (O[rt].ch[(x >> i) & 1] + v == 0) {
      Discard(O[rt].ch[(x >> i) & 1]);
      O[rt].ch[(x >> i) & 1] = 0;
      return;
    }
    rt = O[rt].ch[(x >> i) & 1];
  }
  O[rt].key += v;
}

inline int Merge(int x, int y) {
  if (!O[x].key && !O[y].key) return 0;
  int r;
  if (Q.size()) {r = Q.front(); Q.pop();}
  else r = ++ sz;
  O[r].key = O[x].key + O[y].key;
  O[r].ch[0] = Merge(O[x].ch[0], O[y].ch[0]);
  O[r].ch[1] = Merge(O[x].ch[1], O[y].ch[1]);
  return r;
}

struct SGT {
  SGT *lc, *rc, *fa;
  int key, size, T;
  pii Max;
  SGT() {lc = rc = fa = NULL; T = key = size = 0; Max = mp(0, 0);}
} Pool[2200000], *Sz = Pool;

int n0, top1, top2;
SGT *sta[N << 1], *root;
int que[10000];

inline int Query(int x) {
  int f, w, t, r = 0;
  for (ri i = 19; (~ i); i --) {
    f = 0;
    w = !((x >> i) & 1);
    for (ri j = 1; j <= top2; j ++)
      if (O[O[que[j]].ch[w]].key) {f = 1; break;}
    if (!f) w ^= 1;
    else r ^= 1 << i;
    t = top2;
    top2 = 0;
    for (ri j = 1; j <= t; j ++)
      if (O[O[que[j]].ch[w]].key) que[++ top2] = O[que[j]].ch[w];
  }
  return r;
}

inline void Upd(pii &P, pii A, pii B) {
  if (A.fi > B.fi) P = mp(A.fi, max(A.se, B.fi));
  else P = mp(B.fi, max(B.se, A.fi));
}

inline SGT* Build(SGT *F, int L, int R) {
  if (L == R) {
    sta[L] -> fa = F;
    return sta[L];
  }
  SGT *rt = ++ Sz;
  rt -> fa = F;
  rt -> lc = Build(rt, L, mid);
  rt -> rc = Build(rt, mid + 1, R);
  rt -> key = rt -> lc -> key + rt -> rc -> key;
  rt -> size = rt -> lc -> size + rt -> rc -> size + 1;
  rt -> T = Merge(rt -> lc -> T, rt -> rc -> T);
  Upd(rt -> Max, rt -> lc -> Max, rt -> rc -> Max);
  return rt;
}

inline pii Find(SGT *rt, int L, int R) {
  if (L <= 1 && R >= rt -> key) {
    if (O[rt -> T].key) que[++ top2] = rt -> T;
    return rt -> Max;
  }
  pii r = mp(0, 0);
  if (rt -> lc -> key >= L) r = Find(rt -> lc, L, R);
  if (rt -> lc -> key < R) Upd(r, r, Find(rt -> rc, L - rt -> lc -> key, R - rt -> lc -> key));
  return r;
}

inline void Travel(SGT *rt) {
  if (rt == NULL) return;
  if (rt -> size == 1) {
    if (rt -> key == 1) sta[++ top1] = rt;
    else Discard(rt -> T);
    return;
  }
  Discard(rt -> T);
  Travel(rt -> lc);
  Travel(rt -> rc);
}

inline void Add(int x, int v) {
  SGT *rt = root;
  while (rt -> size != 1) {
    if (rt -> lc -> key >= x) rt = rt -> lc;
    else {
      x -= rt -> lc -> key;
      rt = rt -> rc;
    }
  }
  SGT *rp = ++ Sz, *node = ++ Sz;
  node -> T = ++ sz;
  Insert(node -> T, v, 1);
  node -> Max = mp(v, 0);
  node -> size = node -> key = 1;
  
  (*rp) = (*rt);
  rp -> T = ++ sz;
  Insert(rp -> T, rt -> Max.fi, 1);
  
  rt -> lc = node;
  node -> fa = rt;
  rt -> rc = rp;
  rp -> fa = rt;
  SGT *scape = NULL;
  while (node -> fa != NULL) {
    node = node -> fa;
    node -> size = node -> lc -> size + node -> rc -> size + 1;
    node -> key = node -> lc -> key + node -> rc -> key;
    if (max(node -> lc -> size, node -> rc -> size) > alp * node -> size) scape = node;
  }
  if (scape != NULL) {
    top1 = 0;
    Travel(scape);
    if (scape -> fa == NULL) {
      root = Build(NULL, 1, top1);
      return;
    }
    else {
      rp = scape -> fa;
      if (rp -> lc == scape) rp -> lc = Build(rp, 1, top1);
      else rp -> rc = Build(rp, 1, top1);
      rp -> size = rp -> lc -> size + rp -> rc -> size + 1;
      rp -> key = rp -> lc -> key + rp -> rc -> key;
      Insert(rp -> T, v, 1);
      Upd(rp -> Max, rp -> lc -> Max, rp -> rc -> Max);
    }
  }
  while (rp -> fa != NULL) {
    rp = rp -> fa;
    rp -> size = rp -> lc -> size + rp -> rc -> size + 1;
    rp -> key = rp -> lc -> key + rp -> rc -> key;
    Insert(rp -> T, v, 1);
    Upd(rp -> Max, rp -> lc -> Max, rp -> rc -> Max);
  }
}

inline void Delete(int x) {
  SGT *rt = root;
  while (rt -> size != 1) {
    if (rt -> lc -> key >= x) rt = rt -> lc;
    else {
      x -= rt -> lc -> key;
      rt = rt -> rc;
    }
  }
  int g = rt -> Max.fi;
  rt -> Max.fi = 0;
  rt -> key = 0;
  rt -> T = ++ sz;
  while (rt -> fa != NULL) {
    rt = rt -> fa;
    rt -> key --;
    Insert(rt -> T, g, -1);
    Upd(rt -> Max, rt -> lc -> Max, rt -> rc -> Max);
  }
}

inline void Modify(int x, int v) {
  SGT *rt = root;
  while (rt -> size != 1) {
    if (rt -> lc -> key >= x) rt = rt -> lc;
    else {
      x -= rt -> lc -> key;
      rt = rt -> rc;
    }
  }
  int g = rt -> Max.fi;
  rt -> Max.fi = v;
  rt -> T = ++ sz;
  Insert(rt -> T, v, 1);
  while (rt -> fa != NULL) {
    rt = rt -> fa;
    Insert(rt -> T, g, -1);
    Insert(rt -> T, v, 1);
    Upd(rt -> Max, rt -> lc -> Max, rt -> rc -> Max);
  }
}
int main() {
  int n, m, x;
  scanf("%d%d", &n, &m);
  for (ri i = 1; i <= n; i ++) {
    scanf("%d", &x);
    sta[i] = ++ Sz;
    sta[i] -> T = ++ sz;
    Insert(sta[i] -> T, x, 1);
    sta[i] -> size = sta[i] -> key = 1;
    sta[i] -> Max = mp(x, 0);
  }
  n0 = n;
  root = Build(NULL, 1, n);
  char s[5];
  int lastans = 0, l, r, v, k;
  for (; m; m --) {
    scanf("%s", s);
    if (s[0] == ‘I‘) {
      scanf("%d%d", &x, &v);
      x = (x + lastans) % n0 + 1;
      v = (v + lastans) % 1048576;
      Add(x, v);
      n0 ++;
    }
    else if (s[0] == ‘D‘) {
      scanf("%d", &x);
      x = (x + lastans) % n0 + 1;
      Delete(x);
      n0 --;
    }
    else if (s[0] == ‘C‘) {
      scanf("%d%d", &x, &v);
      x = (x + lastans) % n0 + 1;
      v = (v + lastans) % 1048576;
      Modify(x, v);
    }
    else if (s[0] == ‘F‘) {
      scanf("%d%d", &l, &r);
      l = (l + lastans) % n0 + 1;
      r = (r + lastans) % n0 + 1;
      if (l == r) continue;
      if (l > r) swap(l, r);
      top2 = 0;
      k = Find(root, l, r).se;
      lastans = Query(k);
      printf("%d\n", lastans);
    }
  }
  return 0;
}

  

以上是关于BZOJ 3217: ALOEXT的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3217: ALOEXT

BZOJ3217ALOEXT 替罪羊树+Trie树

bzoj3217ALOEXT 替罪羊树套Trie树

瞎题表

前端学习(3217):prop的基本使用

Bzoj2339--Hnoi2011卡农