HDU4699 Editor(双栈对弹)

题目链接

在这里插入图片描述
1.题目大意:文本编译光标。有如下操作:(1)每次在光标后插入一个元素,光标随即移动到序列尾部(2)在光标前面有元素的情况下删除光标的前一个元素(三)如果光标不在序列头部就将光标左移(四)如果光标不在序列尾部就将光标右移(五)查询当前光标前的最大前缀和

2.第一眼想到,用数组维护所有元素的前缀和和最大前缀和,使用双向链表维护光标。但是头疼的是光标并不指向元素,而是在元素中间,类似电脑鼠标的光标。而且双向链表写起来很麻烦。虽然链表是数据结构的基础,但是实际上能不写链表就不写链表。这里我第一次了解到栈的强大之处:双栈对弹

3.如下图,两个栈构成了整个序列,初始时如果光标没有移动右栈永远是空的,那么不断插入就不断向左栈push即可,光标如我们所期待那样移动:
在这里插入图片描述
如果我们要删除元素,显然直接从左栈删除即可,光标也会如我们所料移动
如果让光标左移,那么将左栈栈顶弹出并push到右栈栈顶:
在这里插入图片描述
同理光标右移,光标的变化也如我们期望

4.至于前缀和,两个数组维护即可,每次查询输出当前左栈长度最大前缀和。不难发现我们只要维护左栈长度即可,插入和右栈左弹实现原理一样,更新当前最大前缀和。删除的话sz–即可

5.其实双向链表也没有那么麻烦,用数组模拟双向链表即可,就是容易把人搞晕。但是能多学一个技能还是要多学,这个黑科技确实强大!

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=1e6+10;
typedef long long ll;
struct Stack{
    ll a[maxn];
    int cur;

    void init(){
        cur=0;
        memset(a,0,sizeof a);
    }

    void push(ll x){
        a[++cur]=x;
    }

    void pop(){
        if(!empty()) cur--;
    }

    ll top(){
        return a[cur];
    }

    int size(){
        return cur;
    }

    int empty(){
        return !cur;
    }
};

ll sum[maxn],Max[maxn];
Stack L,R;

int main()
{
    int n,x,sz;
    char op;
    while(~scanf("%d",&n)){
        L.init(),R.init();
        memset(sum,0,sizeof sum);
        memset(Max,0,sizeof Max);
        Max[0]=-INF;   //注意!!!
        sz=0;
        while(n--){
            cin>>op;
            if(op=='I'){
                scanf("%d",&x);
                L.push(x);
                sz++;
                sum[sz]=sum[sz-1]+x;
                Max[sz]=max(sum[sz],Max[sz-1]);
            }else if(op=='D'){  //和下面两个一样必须判断栈不为空
                if(L.size()){
                    L.pop();
                    sz--;
                }
            }else if(op=='L'){
                if(L.size()){
                    R.push(L.top());
                    L.pop();
                    sz--;
                }
            }else if(op=='R'){  //右移时左栈前缀和更新
                if(R.size()){
                    L.push(R.top());
                    R.pop();
                    sz++;
                    sum[sz]=sum[sz-1]+L.top();
                    Max[sz]=max(sum[sz],Max[sz-1]);
                }
            }else if(op=='Q'){
                scanf("%d",&x);
                printf("%lld\n",Max[x]);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值