hdu 4699 Editor 伸展树 treap复习

题意:对一个数列进行操作,光标位置后面插入一个权值为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;
}


hdu 4699 Editor 伸展树 treap复习

上一篇:leetcode--Power(x,n)


下一篇:LeetCode OJ:First Missing Positive