[置顶] hdu 4699 2个栈维护 or 伸展树
题意:对一个数列进行操作,光标位置后面插入一个权值为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; }