[置顶] 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 [算法] 维护两个栈,一个栈放光标之前的数,另外一个放光标之后的数 在维护栈的同时求最大前缀 ...
随机推荐
- Python写入文件,但是发现文件为空,竟然未写入!
问题描述: fw=open(r'C:\test.txt','w') s="Hello World!" fw.write(s) ========== 此时查看C盘根目录,发现test ...
- SqlServer中的数据类型UniqueIdentifier
SqlServer中的数据类型UniqueIdentifier究竟是什么东东? 该类型一般用来做为主键使用,可用SQL语法的newid()来生成一个唯一的值.我想请问的是,这个值是一个长整型的数据值呢 ...
- 页面导出生成pdf,使用wkhtmltopdf第三方工具
把页面导出生成pdf,这里用到第三方的工具,使用方法中文文档没有找到,网上也没找到网友详细的神作.没有深入研究,所以也不赘述了,当然最基本的使用大多数也够用了,详细参数的官网也没介绍,大家使用的时候, ...
- WinSock - 建立无连接的通信
1.建立一个基于对话框的工程,并在第二步中选择WOSA支持 2.建立客户端 (1)在头文件中添加成员变量 public: CSocket m_clientsocket; (2)每隔一秒钟向服务端发送一 ...
- list view Item 里面有ImageButton
list view Item 里面有ImageButton listview 的item中有ImageButton, 或者 Button. 目的: ImageButton 和 Button的click ...
- 万方数据知识平台 TFHpple +Xpath解析
试了一下.基本上适合全部的检索结果. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loadi ...
- Android菜鸟的成长笔记(4)——你真的理解了吗?
原文:Android菜鸟的成长笔记(4)--你真的理解了吗? 在上一篇中我们查看了QQ的apk源文件中的布局结构,并仿照QQ完成了我们第一个应用的界面,详细请看<Android菜鸟的成长笔记&g ...
- LA - 4043 - Ants
题意:n只蚂蚁,n棵树,每只蚂蚁要连一棵树,连线(直线)不能相交,给出n只蚂蚁和n棵树的坐标,输出n只蚂蚁所配对的树的编号(1 <= n <= 100, -10000 <= 坐标x, ...
- 灵动标签的使用方法 ecms通过运行sql获取须要的记录
在某些条件下,我们要求站点的某页上显示指定的信息, 可是这样的指定假设固定去用代码写死的话,对以后的修改将会是大麻烦: 这时候sql语句的优势就凸显出来,利用sql语句仅仅须要改改数字,就能让显示的内 ...
- [Android学习笔记]Activity
每一个activity都表示一个屏幕,程序把activity呈现给用户,而在activity上实际看到的UI控件,都是View. 故把activity简单理解为view的容器. activity的状态 ...