[置顶] 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;
}
[置顶] hdu 4699 2个栈维护 or 伸展树的更多相关文章
- HDU 4699 - Editor - [对顶栈]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4699 Problem Description Sample Input8I 2I -1I 1Q 3LD ...
- hdu 4699 Editor 模拟栈
思路:刚开始用STL中的栈,一直RE……,之后改为手动模拟栈操作,在注意点细节就可以了!!! 代码如下: #include<cstdio> #include<cstring> ...
- HDU 5033 Building(单调栈维护凸包)
盗张图:来自http://blog.csdn.net/xuechelingxiao/article/details/39494433 题目大意:有一排建筑物坐落在一条直线上,每个建筑物都有一定的高度, ...
- [置顶] hdu 1890 伸展树区间翻转
题意: 给你n个数,每次先输出第i大的数的位置(如果有多个,选下标小的那个),然后每次将第i个位置到第i大的数所在位置之间的数进行翻转. 思路:输入的数组可能有多个相同的值,我们可以进行两次排序把数组 ...
- [置顶] hdu 4418 高斯消元解方程求期望
题意: 一个人在一条线段来回走(遇到线段端点就转变方向),现在他从起点出发,并有一个初始方向, 每次都可以走1, 2, 3 ..... m步,都有对应着一个概率.问你他走到终点的概率 思路: 方向问 ...
- hdu 1754 I Hate It (splay tree伸展树)
hdu 1754 I Hate It 其实我只是来存一下我的splay模板的..请大牛们多多指教 #include<stdio.h> #include<string.h> #i ...
- [置顶] ※数据结构※→☆线性表结构(stack)☆============栈 序列表结构(stack sequence)(六)
栈(stack)在计算机科学中是限定仅在表尾进行插入或删除操作的线性表.栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据.栈 ...
- HDU - 4699 对顶栈
Get到了全新O(1)替代部分伸展树功能的姿势 左栈stk1维护当前信息,右栈stk2维护历史删除信息 题目求的是严格的前缀和(且小于当前指针)那就每次左栈新增时再更新前缀和信息就好 即使把题面换成最 ...
- 【HDU 4699】 Editor
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4699 [算法] 维护两个栈,一个栈放光标之前的数,另外一个放光标之后的数 在维护栈的同时求最大前缀 ...
随机推荐
- Swift - 使用Core Data进行数据持久化存储
一,Core Data介绍 1,Core Data是iOS5之后才出现的一个数据持久化存储框架,它提供了对象-关系映射(ORM)的功能,即能够将对象转化成数据,也能够将保存在数据库中的数据还原成对象. ...
- MsSqlServer bak文件数据导入
MsSqlServer bak文件数据导入 第一步首先在你的数据库中建立一个空数据库 选中新建的数据库 鼠标右键 任务 还原 数据库 这个时候会弹出这种一个框 之后选择原设备 会弹出 点击加入 找到 ...
- python发送post和get请求
python发送post和get请求 get请求: 使用get方式时,请求数据直接放在url中. 方法一. import urllib import urllib2 url = "http: ...
- jquery控制动态生成的gridview中多列checkbox的全选反选及自动判断是否全选状态
动态生成的Gridview的前台html代码如下: <table class="usertableborder" cellspacing="0" ...
- CF437D(The Child and Zoo)最小生成树
题目: D. The Child and Zoo time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- Appium 出现 > error: com.test/.activity1 never started. Current: com.test/.activity2
在apium 运行的时候,会出现提示 activity 没有启动,当前是 activity 出现原因: 出现这种情况是因为 launch activity 再启动 app 之后 无法找到,变成了app ...
- 一个完善的ActiveX Web控件教程
免费打工仔:一个完善的ActiveX Web控件教程 出自Ogre3D开放资源地带 跳转到: 导航, 搜索 原作者 David Marcionek. 翻译 免费打工仔 这个教程可以帮助你快速开发一 ...
- 【Demo 0009】表视图控制器
本章学习要点: 1. 掌握表视图控制器结构; 2. 掌握表视图控制器的基本使用; 3. 掌握表视图表格的基本使用: 4. 掌握自定义表视图表格及 ...
- Python基础 2----Python 基础语法
1 模块导入原理 1 模块是包含函数,类,变量的独立的Python文件 2 导入系统的模块 比如我在家目录下创建一个m.py的文件,我们导入了许多的系统模块,比如time,string等等.这边就类似 ...
- 查找MobileSafari WebKit revision number的方法
Mobile Safari是开源的Mac Safari的iOS版本,然而iOS WebKit并不完全开源,只公开了部分的WebCore和JavaScriptCore.有时需要知道iOS Safari的 ...