[置顶] hdu 4699 2个栈维护 or 伸展树

hdu 4699  Editor

题意:对一个数列进行操作,光标位置后面插入一个权值为x的数,删除光标前的那个数,光标左移一位,光标右移一位,求到k位置的最大的前缀和。。

注意这里的k是在光标之前的,由于这个条件,所以这题又简单的2个栈维护可以解,如果没有这个条件,那么就要用伸展树了。

栈的解法叉姐的解题报告有,我这里说说伸展树的做法, 1.8MS卡过。

我们用cur表示光标在第几个数的右边,size表示数的总个数。

对于操作L: 没有移到最左边就cur--

对于操作R: 没有移到最右边就cur++

对于操作D: 把当前的第cur个位置的节点旋到根,再把第cur-1位置的节点旋到根的左边,令根的左右儿子分别为L,R

那么L一定没有右儿子,把L变为根, R变为L的右儿子。

对于操作I x:把当前的第cur个位置的节点旋到根,在根和根的右儿子之间插入一个新节点。

对于操作Q x:相当于询问1------x区间的最大前缀和。把第0个节点旋到根,把第x-1个节点旋到根的右边。

如何求最大前缀和, 维护一个sum[x]表示区间和,ans[x]表示在x为根的区间里的最大前缀和(注意至少要取一个数)。

伸展树:

 

#include <cstdio>

#include <cstring>

#include <algorithm>

const int maxn = 1000006;

using namespace std;

#define L ch[x][0]

#define R ch[x][1]

#define KT ch[ ch[root][1]][0]

int cur, size;

struct splaytree {

	int sz[maxn], ch[maxn][2], pre[maxn];

	int tot, root;

	int sum[maxn], val[maxn], ans[maxn];

	int sta[maxn], top;



	void rotate(int &x, int f) {

		int y = pre[x], z = pre[y];

		ch[y][!f] = ch[x][f];

		pre[ch[x][f]] = y;

		pre[x] = pre[y];

		if(z) ch[z][ch[z][1] == y] = x;

		ch[x][f] = y;

		pre[y] = x;

		up(y);

	}

	void splay(int &x, int g) {

		while(pre[x] != g) {

			int y = pre[x], z = pre[y];

			if(z == g) rotate(x, ch[y][0] == x);

			else {

				int f = (ch[z][0] == y);

				ch[y][!f] == x ? rotate(y, f) : rotate(x, !f);

				rotate(x, f);

			}

		}

		if(!g) root = x;

		up(x);

	}

	void rto(int k, int g) {

		int x = root;

		while(sz[L] != k) {

			if(sz[L] > k) x = L;

			else {

				k -= sz[L]+1;

				x = R;

			}

		}



		splay(x, g);

	}

	void newNode(int &x, int v, int fa) {

		if(top) x = sta[top--];

		else x = ++tot;

		sz[x] = 1;

		pre[x] = fa;

		L = R = 0;

		sum[x] = ans[x] = val[x] = v;

	}

	void init() {

		top = tot = 0;

		cur = size = 0;

		newNode(root, 0, 0);

		newNode(ch[root][1], 0, root);

	}

	void insert(int k, int v) {

		rto(k, 0);

//debug();

		int x;

		newNode(x, v, root);

		ch[x][1] = ch[root][1];

		pre[ch[x][1]] = x;

		ch[root][1] = x;

		up(x);

		up(root);

	}

	void erase(int k) {

		rto(k, 0);

		rto(k-1, root);

		sta[++top] = root;

		int l = ch[root][0], r = ch[root][1];

		root = l;

		pre[l] = 0;

		ch[l][1] = r;

		pre[r] = l;

		up(l);

	}

	void query(int k) {

		rto(0, 0);

		rto(k+1, root);

		printf("%d\n", ans[KT]);

	}

	void up(int x) {

		sz[x] = sz[L] + sz[R] + 1;

		sum[x] = sum[L] + sum[R] + val[x];

		ans[x] = max(ans[L], sum[L] + max(val[x], 0));

		ans[x] = max(ans[x], sum[L]+ val[x]+max(0, ans[R]));

	}

	void print(int x) {



		printf("node %d, left %d, right %d, pre %d, sum %d, ans %d, val %d\n", x, L, R, pre[x], sum[x], ans[x], val[x]);

        if(L) print(L);

		if(R) print(R);

	}

	void debug() {

	    printf("root = %d cur = %d\n", root, cur);

		print(root);

	}

	void down(int x) {



	}

}spt;

int main() {

	int m, x;

	char op[3];

	while( ~scanf("%d", &m)) {

		spt.init();



		while(m--) {

			scanf("%s", op);

			if(op[0] == 'L') {

                if(cur)cur--;

			}

			else if(op[0] == 'R') {

                if(cur < size)cur++;

			}

			else if(op[0] == 'D') spt.erase(cur--), size--;

			else {

				scanf("%d", &x);

				if(op[0] == 'I') spt.insert(cur++, x), size++;

				else spt.query(x);

			}

		//	spt.debug();

		}

	}

	return 0;

}


 

栈维护:

 

#include <cstdio>

#include <cstring>

#include <stack>

using namespace std;

const int maxn = 1000006;

int dp[maxn], sum[maxn], m, x;

const int inf =  1e9+6;

char op[3];

int l[maxn], r[maxn], t1, t2;

int main() {

    while( ~scanf("%d", &m)) {

        dp[0] = -inf;

        t1 = t2 = 0;

        while(m--) {

            scanf("%s", op);

            if(op[0] == 'I') {

                scanf("%d", &x);

                l[++t1] = x;

                sum[t1] = sum[t1-1] + x;

                dp[t1] = max(dp[t1-1], sum[t1]);

            }

            else if(op[0] == 'L') {

                if(!t1) continue;

                r[++t2] = l[t1--];

            }

            else if(op[0] == 'R') {

                if(!t2) continue;

                l[++t1] = r[t2--];

                sum[t1] = sum[t1-1] + l[t1];

                dp[t1] = max(dp[t1-1], sum[t1]);



            }

            else if(op[0] == 'D') t1--;

            else {

                scanf("%d", &x);

                printf("%d\n", dp[x]);

            }

        }



    }

    return 0;

}


 

 

你可能感兴趣的:(HDU)