[置顶] 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 [算法] 维护两个栈,一个栈放光标之前的数,另外一个放光标之后的数 在维护栈的同时求最大前缀 ... 
随机推荐
- 页面爬虫(获取其他页面HTML)加载到自己页面
			//前台 <div id="showIframe"></div> $(document).ready(function() { var url = &quo ... 
- 使用JDBC调用数据库的存储过程
			本篇讲述如何使用JDBC来调用MySQL数据库中的存储过程.建议在学习如何使用JDBC调用存储过程前,请先了解如何在数据库中使用存储过程. 存储过程是指在数据库系统中,一组为了完成特定功能的SQL语句 ... 
- C#用链式方法
			C#用链式方法表达循环嵌套 情节故事得有情节,不喜欢情节的朋友可看第1版代码,然后直接跳至“三.想要链式写法” 一.起缘 故事缘于一位朋友的一道题: 朋友四人玩LOL游戏.第一局,分别选择位置:中 ... 
- SilkTest Q&A 11
			101. 如何从其他的机器访问脚本? 答案:将包含脚本的文件夹共享出来…非常简单…你可以使用connect()在你本机运行脚本从而使得它们在其他的一些机器上执行…但是其他人无法访问这些脚本,除非你将它 ... 
- Qt之设置QWidget背景色(QStyleOption->drawPrimitive(QStyle::PE_Widget)方法比较有趣)
			QWidget是所有用户界面对象的基类,这意味着可以用同样的方法为其它子类控件改变背景颜色. Qt中窗口背景的设置,下面介绍三种方法. 1.使用QPalette2.使用Style Sheet3.绘图事 ... 
- 基于Adaboost的人脸检测算法
			AdaBoost算法是一种自适应的Boosting算法,基本思想是选取若干弱分类器,组合成强分类器.根据人脸的灰度分布特征,AdaBoost选用了Haar特征[38].AdaBoost分类器的构造过程 ... 
- 全民Scheme(0):lat的定义
			接下来我会写一写Scheme的学习笔记.嗯,Scheme是属于小众的语言,但合适用来教学的. 什么是lat,就是遍历list里的每一个S-expression,假设发现当中某个不是atom的,则返回f ... 
- WinRarHelper帮助类
			WinRarHelper帮助类 关于本文档的说明 本文档使用WinRAR方式来进行简单的压缩和解压动作,纯干货,实际项目这种压缩方式用的少一点,一般我会使用第三方的压缩dll来实现,就如同我上一个压缩 ... 
- apk应用的反编译和源代码的生成
			对于反编译一直持有无所谓有或无的态度.经过昨天一下午的尝试,也有了点心得和体会: 先给大家看看编译的过程和我们反编译的过程概图吧: 例如以下是反编译工具的根文件夹结构: 三个目录也实际上是下面三个步骤 ... 
- 用qsort排序
			 冒泡,快排都是常见的排序方法,这里介绍用头文件里的qsort函数排序.只是自己要先一个cmp函数. #include<stdlib.h>//qsort的头文件 int a[100]= ... 
