• [置顶] 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
    ", 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
    ", 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
    ", 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
    ", dp[x]);
                }
            }
    
        }
        return 0;
    }
    


  • 相关阅读:
    C# winform窗体自动停靠控件
    C# winform treeview checkbox 选中 循环 遍历
    解决WinForm(C#)中MDI子窗体最大化的问题
    tabcontrol的alignment属性设置成Left或Right时,tabPage的text内
    用伪随机数生成器Random生成随机数序列
    C#限制MDI子窗体重复打开——C#判断窗体是否已经打开 多种方法 20120626更新
    管理软件中融入“人、时间、流程”维度,提升软件社会价值
    如何让管理软件提升企业战略执行力
    2007年11月17日上午 ITIL与ITSM QQ群聊天记录: 欢迎加入QQ群:48132184
    Sharepoint 站点下应用程序虚拟路径下出现"不能进行输出缓存处理",错误ID 5787 解决方法
  • 原文地址:https://www.cnblogs.com/riskyer/p/3285562.html
Copyright © 2020-2023  润新知