[代码] bzoj 1500 维修数列(无旋treap)

- 传送门 -

 http://www.lydsy.com/JudgeOnline/problem.php?id=1500
 

1500: [NOI2005]维修数列

Time Limit:?10 Sec??Memory Limit:?64 MB
Submit:?15301??Solved:?5063

Description

Input

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

HINT

- 代码 -

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <ctime>
#include <cstdlib>
#define pii pair<int, int>
#define mp make_pair
#define ls C[rt][0]
#define rs C[rt][1]
using namespace std;

template <typename ty> void read(ty &x) {
  x = 0; int f = 1; char ch = getchar();
  while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); }
  while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); }
  x *= f;
}
template <typename ty> ty Max(ty a, ty b) { return a > b ? a : b; }
template <typename ty> ty Min(ty a, ty b) { return a < b ? a : b; }
template <typename ty> int Chkmin(ty a, ty b) { return a > b ? a = b, 1 : 0; }
template <typename ty> int Chkmax(ty a, ty b) { return a < b ? a = b, 1 : 0; }

typedef long long LL;
typedef double db;

const int inf = 0x7fffffff;
const int N = 5e5 + 160;

int V[N], C[N][2], S[N], STK[N], KEY[N];
int TAG[N], REV[N], A[N], Q[4000016];
int LM[N], RM[N], TM[N], T[N];
int root, n, m, sz, tot;
int pos, t, c;

char OP[160];

void pushtag(int rt, int val) {

  if (!rt) return;
  V[rt] = val;
  T[rt] = S[rt] * val;
  LM[rt] = RM[rt] = TM[rt] = Max(val, val * S[rt]);
  TAG[rt] = 1;

}

void pushrev(int rt) {

  if (!rt) return;
  swap(C[rt][0], C[rt][1]);
  swap(LM[rt], RM[rt]);
  REV[rt] ^= 1;

}

void pushup(int rt) {

  if (!rt) return;
  S[rt] = S[ls] + S[rs] + 1;
  T[rt] = T[ls] + T[rs] + V[rt];
  LM[rt] = Max(LM[ls], T[ls] + V[rt] + Max(LM[rs], 0));
  RM[rt] = Max(RM[rs], T[rs] + V[rt] + Max(RM[ls], 0));
  TM[rt] = Max(TM[ls], Max(TM[rs], V[rt] + Max(LM[rs], 0) + Max(RM[ls], 0)));

}

void pushdown(int rt) {

  if (!rt) return;

  if (TAG[rt]) {

    pushtag(ls, V[rt]);
    pushtag(rs, V[rt]);
    TAG[rt] = REV[rt] = 0;

  }

  if (REV[rt]) {

    pushrev(ls);
    pushrev(rs);
    REV[rt] = 0;

  }

}

int new_node() {

  int a, b;
  read(a);
  if (tot) b = Q[tot--];
  else b = ++sz;
  V[b] = a; KEY[b] = rand();
  C[b][0] = C[b][1] = 0;
  S[b] = 1; TAG[b] = REV[b] = 0;
  LM[b] = RM[b] = TM[b] = T[b] = a;
  return b;

}

int build(int s) {

  int lst = 0, top = 0;
  for (int i = 1; i <= s; ++ i) {

    int tmp = new_node(); lst = 0;
    while (top && KEY[tmp] < KEY[STK[top]]) {
      pushup(STK[top]);
      lst = STK[top];
      STK[top--] = 0;
    }
    if (lst) C[tmp][0] = lst;
    if (top) C[STK[top]][1] = tmp;
    STK[++top] = tmp;

  }

  while (top) pushup(STK[top--]);
  return STK[1];

}

pii split(int rt, int k) {

  if (!rt) return mp(0, 0);

  pii tmp;
  pushdown(rt);

  if (k > S[C[rt][0]]) {
    tmp = split(C[rt][1], k - S[C[rt][0]] - 1);
    C[rt][1] = tmp.first; pushup(rt); tmp.first = rt;
  }
  else {
    tmp = split(C[rt][0], k);
    C[rt][0] = tmp.second; pushup(rt); tmp.second = rt;
  }

  return tmp;

}

int merge(int ra, int rb) {

  if (!ra) return rb;
  if (!rb) return ra;

  pushdown(ra);
  pushdown(rb);

  if (KEY[ra] < KEY[rb]) {
    C[ra][1] = merge(C[ra][1], rb);
    pushup(ra); return ra;
  }
  else {
    C[rb][0] = merge(ra, C[rb][0]);
    pushup(rb); return rb;
  }

}

void recycle(int rt) {

  if (!rt) return;
  Q[++tot] = rt;
  recycle(C[rt][0]);
  recycle(C[rt][1]);

}

void work1() {

  read(pos); read(t);
  pii a = split(root, pos);
  root = merge(a.first, merge(build(t), a.second));

}

void work2() {

  read(pos); read(t);
  pii a = split(root, pos - 1);
  pii b = split(a.second, t);
  recycle(b.first);
  root = merge(a.first, b.second);

}

void work3() {

  read(pos); read(t); read(c);
  if (!t) return;
  pii a = split(root, pos - 1);
  pii b = split(a.second, t);
  pushtag(b.first, c);
  root = merge(a.first, merge(b.first, b.second));

}

void work4() {

  read(pos); read(t);
  if (!t) return;
  pii a = split(root, pos - 1);
  pii b = split(a.second, t);
  pushrev(b.first);
  root = merge(a.first, merge(b.first, b.second));

}

void work5() {

  read(pos); read(t);
  if (!t) { printf("0\n"); return; }
  pii a = split(root, pos - 1);
  pii b = split(a.second, t);
  printf("%d\n", T[b.first]);
  root = merge(a.first, merge(b.first, b.second));

}

void work6() { printf("%d\n", TM[root]); }

int main () {

  read(n); read(m);

  LM[0] = RM[0] = TM[0] = V[0] = -inf;
  root = build(n);
  for (int i = 1; i <= m; ++ i) {
    scanf("%s", OP);
    if (OP[0] == 'I') work1();
    if (OP[0] == 'D') work2();
    if (OP[2] == 'K') work3();
    if (OP[0] == 'R') work4();
    if (OP[0] == 'G') work5();
    if (OP[2] == 'X') work6();
  }

  return 0;

}
时间: 2024-08-29 18:13:19

[代码] bzoj 1500 维修数列(无旋treap)的相关文章

[代码] bzoj 3224 普通平衡树(无旋treap)

- 传送门 - http://www.lydsy.com/JudgeOnline/problem.php?id=3224 3224: Tyvj 1728 普通平衡树 Time Limit:?10 Sec??Memory Limit:?128 MB Submit:?17311??Solved:?7553 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 1. 插入x数 2. 删除x数(若有多个相同的数,因只删除一个) 3. 查询x数的排名(若有多

BZOJ 1500 维修数列

Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行. Sample Input 9 8 2 -6 3 5 1 -5 -3 6 3 GET-SUM 5 4 MAX-SUM INSERT 8 3 -5 7 2 DELETE 12

[BZOJ3223]文艺平衡树 无旋Treap

3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 Input 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2--n-1,n)  m表示翻转操作次数接下来m行每行两个数[l,r] 数据保证 1<=l<

[您有新的未分配科技点]无旋treap:从好奇到入门(例题:bzoj3224 普通平衡树)

今天我们来学习一种新的数据结构:无旋treap.它和splay一样支持区间操作,和treap一样简单易懂,同时还支持可持久化. 无旋treap的节点定义和treap一样,都要同时满足树性质和堆性质,我们还是用rand()来实现平衡 而无旋treap与treap不同的地方,也是其核心,就是它不旋转用两个新的核心函数:merge函数(合并两棵子树)和split函数(分裂出某棵树的前k个节点,并且作为一棵树返回) 首先看merge函数,它是一个递归实现的过程,先看代码: 1 Treap *merge(

【算法学习】Fhq-Treap(无旋Treap)

Treap--大名鼎鼎的随机二叉查找树,以优异的性能和简单的实现在OIer们中广泛流传. 这篇blog介绍一种不需要旋转操作来维护的Treap,即无旋Treap,也称Fhq-Treap. 它的巧妙之处在于只需要分离和合并两种基本操作,就能实现任意的平衡树常用修改操作. 而不需要旋转的特性也使编写代码时不需要考虑多种情况和复杂的父亲儿子关系的更新,同时降低了时间复杂度. 此外,它还可以方便地支持可持久化,实在是功能强大. 接下来系统性地介绍一下无旋Treap的原理和实现,最后讲解一下应用和例题.

[Bzoj3223][Tyvj1729] 文艺平衡树(splay/无旋Treap)

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3223 平衡树处理区间问题的入门题目,普通平衡树那道题在维护平衡树上是以每个数的值作为维护的标准,而处理区间问题时,维护平衡树的应该是每个位置的下标,所以平衡树中序遍历时应该是当前区间的样子.例如: {1 2 3 4 5}翻转区间1 3,则中序遍历应该输出{3,2,1,4,5}. 提供splay和无旋Treap的做法. splay做法: 1 #include<bits/stdc++.h>

模板 - 数据结构 - 无旋Treap / FHQ Treap

普通平衡树: #include<bits/stdc++.h> using namespace std; typedef long long ll; #define ls(p) ch[p][0] #define rs(p) ch[p][1] const int MAXN = 100000 + 5; int val[MAXN], ch[MAXN][2], rnd[MAXN], siz[MAXN], tot, root; void Init() { tot = root = 0; } void Pu

[BZOJ1588][HNOI2002]营业额统计 无旋Treap

[HNOI2002]营业额统计 时间限制: 5 Sec  内存限制: 162 MB 题目描述 营业额统计 Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额.分析营业情况是一项相当复杂的工作.由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题.经济管理学上定

BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

不难...treap + 启发式合并 + 并查集 搞搞就行了 ---------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #define rep(i, n) for(int i = 0; i &l