题意:对一个数列进行操作,光标位置后面插入一个权值为x的数,删除光标前的那个数,光标左移一位,光标右移一位,求1到k位置的最大的前缀和。。
思路:注意这里的k是在光标之前的,由于这个条件,所以这题又简单的2个栈维护可以解,如果没有这个条件,那么就要用伸展树了。之前写过这题题解,数组的splay和栈都写过 以前的链接
其它操作都没问题,这里主要讲讲 询问操作。
对于操作Q x:相当于询问1------x区间的最大前缀和。把第0个节点旋到根,把第x-1个节点旋到根的右边。
如何求最大前缀和, 每个节点维护一个sum表示区间和,ans表示在为根的区间里的最大前缀和(注意至少要取一个数)。写个pushup更新ans即可。
splay:这题主要是为了 给我的新版splay练手, 新版的splay有很大改进, 大大缩短了rotate, splay函数的成型时间,减少了错误率,而且代码简洁。
treap:用可持久化思想的那种treap, 相比splay而言,insert, delete, query操作更加顺手, 在splay中写这些操作时不时会出现错误。 这种treap其实可以实现与splay一样的功能,包括有 pushdown的一些问题,成段插入, 成段删除等,总体来说写treap会更省事省力。
2份代码在下面:
splay code:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1000006; struct node; node *root, *null; struct node { node *c[2], *fa; int sz, id; //id表示在内存中节点的标号,方便debug int val, sum, ans; inline bool d() { return fa->c[1] == this; } inline void fix(int d, node *x) { //修改节点父亲儿子关系 c[d] = x, x->fa = this; } void rot() { //把this节点 上旋 node *y = fa, *z = y->fa; bool f = d(); z->fix(y->d(), this); y->fix(f, c[!f]); fix(!f, y); y->up(); } void splay(node *g) { //把this节点旋到g节点下面 while (fa != g) { node *y = fa, *z = y->fa; if(z == g) rot(); else if(y->d() == d()) y->rot(), rot(); //3点共线 else rot(), rot(); } up(); if(g == null) root = this; } void up() { sz = c[0]->sz + c[1]->sz + 1; sum = c[0]->sum + c[1]->sum + val; if(c[0] == null) ans = val + max(0, c[1]->ans); else ans = max(c[0]->ans, c[0]->sum + val + max(0, c[1]->ans)); } void out() { //输出节点信息,debug用 printf("v%d fa%d ls%d rs%d lsz%d rsz%d val%d sum%d ans%d\n", id, fa->id, c [0]->id, c[1]->id, c[0]->sz, c[1]->sz, val, sum, ans); } }; struct splayTree { node mem[maxn]; int tot; node* newNode(int v = 0, node *fa = null) { node *x = &mem[tot]; x->val = x->sum = x->ans = v; x->sz = 1, x->id = tot++; x->fa = fa; x->c[0] = x->c[1] = null; return x; } void rto(int k, node *g) { k++; //一开始有一个最小的节点 node *x = root; while (true) { int v = x->c[0]->sz + 1; if(v == k) break; if(k > v) { k -= v; x = x->c[1]; } else x = x->c[0]; } x->splay(g); } //分界线, 以上代码原封不动 #define kt root->c[1]->c[0] void init() { //初始化新建最小点和最大点 cur = size = tot = 0; null = newNode(), null->sz = 0; root = newNode(); root->c[1] = newNode(0, root); root->up(); } void ins(int k, int v) { rto(k, null); node *x = newNode(v, root); x->fix(1, root->c[1]); root->fix(1, x); x->up(), root->up(); } void del(int k) { rto(k - 1, null); rto(k, root); root->fix(1, root->c[1]->c[1]); root->c[1]->up(), root->up(); } int query(int k) { rto(0, null); rto(k + 1, root); return kt->ans; } void show(node *x) { //debug用 if(x == null) return; x->out(); show(x->c[0]); show(x->c[1]); } void show() { //debug用 puts("************"); printf("root:%d\n", root->id); show(root); } }t; int cur, size; int main() { int m; while (~scanf("%d", &m)) { t.init(); char op[3]; int v; while (m--) { scanf("%s", op); if(op[0] == ‘L‘ && cur) cur--; if(op[0] == ‘R‘ && cur != size) cur++; if(op[0] == ‘D‘) t.del(cur), cur--, size--; if(op[0] == ‘Q‘) { scanf("%d", &v); printf("%d\n", t.query(v)); } if(op[0] == ‘I‘) { scanf("%d", &v); t.ins(cur, v); size++, cur++; } } } return 0; }
treap code:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct node; node *null, *root; struct node { node *c[2]; int val, ans, sum; int sz, r; inline void up() { sz = c[0]->sz + c[1]->sz + 1; sum = c[0]->sum + c[1]->sum + val; if(c[0] == null) ans = val + max(0, c[1]->ans); else ans = max(c[0]->ans, c[0]->sum + val + max(0, c[1]->ans)); } }; const int maxn = 100005; node mem[maxn]; int tot; node* newNode(int v = 0) { node *x = &mem[tot++]; x->val = x->sum = x->ans = v; x->c[0] = x->c[1] = null; x->sz = 1, x->r = rand(); return x; } void merge(node *&o, node *a, node *b) { if(a == null) o = b; else if(b == null) o = a; else if(a->r < b->r) { o = a; merge(o->c[1], a->c[1], b); o->up(); } else { o = b; merge(o->c[0], a, b->c[0]); o->up(); } } void split(node *o, node *&a, node *&b, int k) { if(!k) { a = null; b = o; } else if(o->sz <= k) { a = o; b = null; } else if(o->c[0]->sz >= k) { b = o; split(o->c[0], a, b->c[0], k); b->up(); } else { a = o; split(o->c[1], a->c[1], b, k - o->c[0]->sz - 1); a->up(); } } void out(node *x) { if(x == null) return; printf("%d\n", x->val); out(x->c[0]); out(x->c[1]); } void ins(int k, int v) { node *a, *b, *c; split(root, a, b, k); out(a);// out(b); c = newNode(v); merge(a, a, c); merge(root, a, b); } void del(int k) { node *a, *b, *c; split(root, a, b, k - 1); split(b, b, c, 1); merge(root, a, c); } int query(int k) { node *a, *b, *c; split(root, a, b, k); int ret = a->ans; merge(root, a, b); return ret; } int cur, size; void init() { cur = tot = size = 0; null = newNode(), null->sz = 0; root = null; } int main() { int m; while (~scanf("%d", &m)) { init(); char op[3]; int v; while (m--) { scanf("%s", op); if(op[0] == ‘L‘ && cur) cur--; if(op[0] == ‘R‘ && cur != size) cur++; if(op[0] == ‘D‘) del(cur), cur--, size--; if(op[0] == ‘Q‘) { scanf("%d", &v); printf("%d\n", query(v)); } if(op[0] == ‘I‘) { scanf("%d", &v); ins(cur, v); size++, cur++; } } } return 0; }