您的位置:首页 > 其它

hdu 4699 Editor 伸展树 treap复习

2014-01-29 23:34 549 查看
题意:对一个数列进行操作,光标位置后面插入一个权值为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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息