HDU 4699 Editor

题意: 有一个光标,支持左移,右移,插入数字,删除数字,询问1~k最大前缀和。

解法: 用一个数据结构维护序列,答案可以DP出来。具体见代码。

手贱写了个Splay。其实链表就可以的吧。

本人第二弹Splay,支持旋转,插入,删除,查询第k位置。距离能当模板用貌似还有一段距离。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define clr(a,b) memset(a,b,sizeof(a));
#define REP(i,a,b) for(int i=(a); i<(b); i++)
const int INF = ~0u>>1;

// Splay
struct Node {
    Node *ch[2];
    int size;
    int val;
    int cmp(int x) const {
        if(x == ch[0]->size + 1) return -1;
        return x < ch[0]->size + 1 ? 0 : 1;
    }
    void pushup() {
        size = ch[0]->size + ch[1]->size + 1;
    }
};

Node *nill,*root;
int point;  // 光标位置


void init() {
    nill = new Node();
    nill->ch[0] = nill->ch[1] = nill;
    nill->size = 0;
}

void rotate(Node* &o, int d) {
    Node* tt = o;
    o = o->ch[d^1];
    tt->ch[d^1] = o->ch[d];
    o->ch[d] = tt;
    o->ch[d]->pushup();
    o->pushup();
}

// 将左数第k个元素旋至根
void splay(Node* &o, int k) {
    if(o == nill) return;
    int d = o->cmp(k);
    if(d == 1) k -= o->ch[0]->size + 1;
    if(d != -1) {
        Node* p = o->ch[d];
        int d2 = p->cmp(k);
        int k2 = (d2 == 0 ? k : k - p->ch[0]->size - 1);
        if(d2 != -1) {
            splay(p->ch[d2],k2);
            if(d == d2) rotate(o,d^1); else rotate(o->ch[d],d);
        }
        rotate(o,d^1);
    }
}

void INIT() {
    root = new Node();
    root->ch[0] = nill;
    root->ch[1] = new Node();
    root->ch[1]->ch[0] = root->ch[1]->ch[1] = nill;
    root->size = 2;
    root->ch[1]->size = 1;
}


void Insert(Node* &o, int pos, int x) {
    splay(o,pos-1);
    splay(o->ch[1],1);
    o->ch[1]->ch[0] = new Node();
    o->ch[1]->ch[0]->ch[0] = o->ch[1]->ch[0]->ch[1] = nill;
    o->ch[1]->ch[0]->size = 1;
    o->ch[1]->ch[0]->val = x;
    o->ch[1]->pushup();
    o->pushup();
}

void Delete(Node* &o, int pos) {
    splay(o,pos);
    splay(o->ch[0],pos-1);
    Node* tt = o;
    o=o->ch[0];
    o->ch[1] = tt->ch[1];
    delete tt;
    o->pushup();
}

int query(Node* &o, int k) {
    splay(o,k);
    return o->val;
}

const int MAXN = 1001000;
int C[MAXN];
int mm[MAXN];

void Remove_Tree(Node* o) {
    if(o == nill) return ;
    Remove_Tree(o->ch[0]);
    Remove_Tree(o->ch[1]);
    delete o;
}

int main() {
    int tot;
    int nq;
    init();
    mm[0] = -INF;
    while(~scanf("%d", &nq)) {
        INIT();
        point = 2;
        char s[2];
        int x;
        tot = 2;
        while(nq--) {
            scanf("%s", s);
            if(s[0] == 'I') {   // 在point插入一个数x,并且point后移
                scanf("%d", &x);
                Insert(root,point,x);
                C[point-1] = C[point-2] + x;
                mm[point-1] = max(mm[point-2], C[point-1]);
                point ++ ;
                tot ++ ;
            }
            else if(s[0] == 'D') {  // 把point位置前的数删除,并且point前移
                if(point == 2) continue;
                Delete(root,point-1);
                point -- ;
                tot -- ;
            }
            else if(s[0] == 'L') {  // point前移(在最前时不动)
                if(point > 2) point -- ;
            }
            else if(s[0] == 'R') {  // point后移(在最后时不动)
                if(point < tot) {
                    int tt = query(root,point);
                    C[point-1] = C[point-2] + tt;
                    mm[point-1] = max(mm[point-2], C[point-1]);
                    point ++;
                }
            }
            else if(s[0] == 'Q') {  // 询问1~x范围内的最大前缀和
                scanf("%d", &x);
                printf("%d\n", mm[min(x,point-2)]);
            }
        }
        Remove_Tree(root);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值