lydsy 1500 [NOI2005]维修数列 (Treap版)

来源:互联网 发布:百中搜优化 编辑:程序博客网 时间:2024/05/29 15:35

题意: 数列兄出来受死吧。。这次要求支持插入,删除,区间修改,区间翻转,区间求和,求和最大的子列的和。

解法: 没什么能说的了,一些细节写在了注释里。

/* **********************************************Author      : NeroCreated Time: 2013/9/5 16:51:21Problem id  : lydsy 1500Problem Name: [NOI2005]维修数列 *********************************************** */#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define REP(i,a,b) for(int i=(a); i<(int)(b); i++)#define clr(a,b) memset(a,b,sizeof(a))struct Node {    Node *l, *r;    int v,sum,size;    int lms,rms,tms;    int cover,rev,w;        void up() {        sum = tms = lms = rms = v;        size = 1;        if(l) sum += l->sum, size += l->size;        if(r) sum += r->sum, size += r->size;        // 处理左端最大和        if(l) {            lms = l->lms;            lms = max(lms, l->sum + v);            if(r) lms = max(lms, l->sum + v + r->lms);        } else if(r) {            lms = max(lms, v + r->lms);        }        // 处理右端最大和        if(r) {            rms = r->rms;            rms = max(rms, r->sum + v);            if(l) rms = max(rms, r->sum + v + l->rms);        } else if(l) {            rms = max(rms, v + l->rms);        }        // 处理子段最大和        if(l) {            tms = max(tms, l->tms);            tms = max(tms, l->rms + v);        }        if(r) {            tms = max(tms, r->tms);            tms = max(tms, r->lms + v);        }        if(l && r) tms = max(tms, l->rms + v + r->lms);    }    void down() {        if(cover) {            if(l) {                l->v = v;                l->sum = v * l->size;                if(v >= 0) l->lms = l->rms = l->tms = l->sum;                else l->lms = l->rms = l->tms = v;                l->cover = 1;            }            if(r) {                r->v = v;                r->sum = v * r->size;                if(v >= 0) r->lms = r->rms = r->tms = r->sum;                else r->lms = r->rms = r->tms = v;                r->cover = 1;            }            cover = 0;        }        // 注意处理翻转时左右端最大值也要交换        // lazy的思想是在保证当前节点和两个子节点的信息真实的情况下尽量偷懒        if(rev) {            swap(l,r);            if(l) l->rev ^= 1,swap(l->lms,l->rms);            if(r) r->rev ^= 1,swap(r->lms,r->rms);            rev = 0;        }    }}*root = NULL, *list = NULL;// 节点的回收重复利用// fhq神牛的随机数生成器- -int ran() {    static int ranx = 123654789;    ranx += (ranx << 2) + 1;    return ranx;}void New_node(Node *&o, int val) {    if(list == NULL) {        Node *tt = new Node[10000];        for(int i = 0; i < 10000; i ++) {            tt[i].r = list;            tt[i].w = ran();            list = tt + i;        }    }    o = list;    list = list->r;    o->l = o->r = NULL;    o->v = o->sum = o->lms = o->rms = o->tms = val;    o->rev = o->cover = 0;    o->size = 1;}void Reuse(Node *o) {     if(o == NULL) return ;    Reuse(o->l);    Reuse(o->r);    o->r = list;    list = o;}inline int sz(Node *o) { return o ? o->size : 0; }// 砍树void cut(Node *o, Node *&p, Node *&q, int num) {    if(num == 0) {        p = NULL; q = o;    } else if(num == sz(o)) {        p = o; q = NULL;    } else {        o->down();        if(sz(o->l) >= num) {            q = o;            cut(o->l, p, q->l, num);            q->up();        } else {            p = o;            cut(o->r, p->r, q, num - sz(o->l) - 1);            p->up();        }    }}// 合并void merge(Node *&o, Node *p, Node *q) {    if(!p || !q) {        o = p ? p : q;    } else {        if(p->w > q->w) {            p->down();            o = p;            merge(o->r, p->r, q);        } else {            q->down();            o = q;            merge(o->l, p, q->l);        }        o->up();    }}// 递归插入,否则每次都合并太深要超时Node* Ins(int x) {    if(x == 0) return NULL;    if(x == 1) {        int d;        Node *a;        scanf("%d", &d);        New_node(a,d);        return a;    }    Node *a, *b;    int m = x >> 1;    a = Ins(m);    b = Ins(x-m);    merge(a,a,b);    return a;}// 在第pos个数后面插入x个数void Insert(int pos, int x) {    int d;    Node *a, *b, *c, *t;    cut(root,a,b,pos);    c = Ins(x);    merge(a,a,c);    merge(root,a,b);}// 从第pos个数开始连续删x个数void Remove(int pos, int x) {    Node *a, *b, *c;    cut(root,a,b,pos-1);    cut(b,b,c,x);    Reuse(b);    merge(root,a,c);}// 将第pos个数开始的x个数位置翻转void Reverse(int pos, int x) {    Node *a, *b, *c;    cut(root,a,b,pos-1);    cut(b,b,c,x);    b->rev ^= 1;    swap(b->lms,b->rms);    merge(a,a,b);    merge(root,a,c);}// 求第pos个数开始的连续x个数的和int Get_sum(int pos, int x) {    if(x == 0) return 0;    Node *a, *b, *c;    cut(root,a,b,pos-1);    cut(b,b,c,x);    int ret = b->sum;    merge(a,a,b);    merge(root,a,c);    return ret;}// 将第pos个数开始的x个数修改为dvoid Change(int pos, int x, int d) {    Node *a, *b, *c;    cut(root,a,b,pos-1);    cut(b,b,c,x);    b->v = d;    b->cover = 1;    b->rev = 0;    b->sum = d * sz(b);    if(d >= 0) b->lms = b->tms = b->rms = b->sum;    else b->lms = b->tms = b->rms = d;    merge(a,a,b);    merge(root,a,c);}int main() {    int n,m,x,pos,c;    char s[20];    scanf("%d%d", &n, &m);    Insert(0,n);    while(m --) {        scanf("%s", s);        if(s[0] == 'I') {            scanf("%d%d", &pos, &x);            if(x != 0) Insert(pos,x);        } else if(s[0] == 'D') {            scanf("%d%d", &pos, &x);            if(x != 0) Remove(pos,x);        } else if(s[0] == 'R') {            scanf("%d%d", &pos, &x);            if(x > 1) Reverse(pos,x);        } else if(s[0] == 'G') {            scanf("%d%d", &pos, &x);            printf("%d\n", Get_sum(pos,x));        } else if(s[2] == 'K') {            scanf("%d%d%d", &pos, &x, &c);            if(x != 0) Change(pos,x,c);        } else {            if(root == NULL) puts("0");            else printf("%d\n", root->tms);        }    }    return 0;}

原创粉丝点击