BZOJ 1500 NOI 2005 维修数列 Splay

题意:见下图


传说级别的NOI数据结构神题,像我这种弱渣花了一下午的时间才A掉,最后发现竟然是边界值的问题没处理好。。


这个题对Splay的所有操作基本是全了。

插入:新建一颗Splay Tree,然后把对应节点Splay到根的右儿子上,再把新建的树连上。

删除:把要删除的区间Splay到根的右儿子的左儿子上,递归free掉。(这里可以用数组优化,可以避免递归free节省时间)

修改,翻转:打标记,在需要的时候下传标记,和线段树差不多,翻转标记下传时,要将左右儿子的左右儿子分别交换。

求和:维护一个sum域。

求最大子列和:与线段树类似。维护一个区间从左边开始连续最大值,从右边开始连续最大值,整体的连续最大值。更新的时候注意下细节。不会的可以先去写vijos的小白逛公园,线段树的最大子列和,要比这个简单一些。详情见代码。


CODE(BZOJ5988ms):


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 600010
#define INF 0x7f7f7f7f
using namespace std;
const char INSERT[] = "INSERT";
const char DELETE[] = "DELETE";
const char REVERSE[] = "REVERSE";
const char GET_SUM[] = "GET-SUM";
const char MAX_SUM[] = "MAX-SUM";
const char MAKE_SAME[] = "MAKE-SAME";
 
struct Complex{
    int val,size;
    bool change,reverse;
    int change_into;
    int sum;
    int l,r,all;
    Complex *son[2],*father;
     
    bool Check() {
        return father->son[1] == this;
    }
    void Combine(Complex *a,bool dir) {
        son[dir] = a;
        a->father = this;
    }
    void Reverse() {
        reverse ^= 1;
        swap(son[0],son[1]);
        swap(l,r);
    }
    void Change(int x) {
        val = x;
        sum = x * size;
        l = r = all = max(sum,val);
        change = true;
        change_into = x;
    }
}none,*nil = &none,*root = nil;
 
void Pretreatment();
inline Complex *NewComplex(int x);  
inline void Rotate(Complex *a,bool dir);
inline void Splay(Complex *a,Complex *aim);
Complex *BuildTree(int l,int r);
inline void SplaySeg(int st,int ed);    
inline void PushUp(Complex *a); 
inline void PushDown(Complex *a);
void Delete(Complex *a);
Complex *FindK(Complex *a,int k);
 
void Print(Complex *a)
{
    if(a == nil)    return ;
    PushDown(a);
    PushUp(a);
    Print(a->son[0]);
    printf("%d ",a->val);
    Print(a->son[1]);
}
 
int cnt,asks;
int pos,num;
 
int temp[MAX];
char s[20];
 
int main()
{
    cin >> cnt >> asks;
    Pretreatment();
    for(int i = 1;i <= cnt; ++i) 
        scanf("%d",&temp[i]);
    root = BuildTree(0,cnt + 1);
    root->father = nil;
    for(int i = 1;i <= asks; ++i) {
        scanf("%s",s);
        if(!strcmp(s,INSERT)) {
            scanf("%d%d",&pos,&cnt),pos++;
            for(int i = 1;i <= cnt; ++i)
                scanf("%d",&temp[i]);
            Splay(FindK(root,pos),nil);
            Splay(FindK(root,pos + 1),root);
            root->son[1]->Combine(BuildTree(1,cnt),false);
            PushUp(root->son[1]),PushUp(root);
        }
        else if(!strcmp(s,DELETE)) {
            scanf("%d%d",&pos,&cnt);
            SplaySeg(pos,pos + cnt - 1);
            Delete(root->son[1]->son[0]);
            root->son[1]->son[0] = nil;
            PushUp(root->son[1]),PushUp(root);
        }
        else if(!strcmp(s,MAKE_SAME)) {
            scanf("%d%d%d",&pos,&cnt,&num);
            SplaySeg(pos,pos + cnt - 1);
            root->son[1]->son[0]->Change(num);
            PushUp(root->son[1]),PushUp(root);           
        }
        else if(!strcmp(s,REVERSE)) {
            scanf("%d%d",&pos,&cnt);
            SplaySeg(pos,pos + cnt - 1);
            root->son[1]->son[0]->Reverse();
            PushUp(root->son[1]),PushUp(root);           
        }
        else if(!strcmp(s,GET_SUM)) {
            scanf("%d%d",&pos,&cnt);
            SplaySeg(pos,pos + cnt - 1);
            printf("%d\n",root->son[1]->son[0]->sum);
        }
        else if(!strcmp(s,MAX_SUM)) {
            int temp = root->size;
            Splay(FindK(root,1),nil);
            Splay(FindK(root,temp),root);
            printf("%d\n",root->son[1]->son[0]->all);
        }
    }
    return 0;
}
 
void Pretreatment()
{
    nil->son[0] = nil->son[1] = nil;
    nil->father = nil;
    nil->size = 0;
    nil->all = -INF;
    temp[0] = temp[cnt + 1] = -INF;
}
 
inline Complex *NewComplex(int x)
{
    Complex *re = new Complex();
    re->son[0] = re->son[1] = nil;
    re->size = 1;
    re->sum = re->l = re->r = re->all = re->val = x;
    re->change = re->reverse = false;
    return re;
}
 
inline void Rotate(Complex *a,bool dir)
{
    Complex *f = a->father;
    PushDown(f),PushDown(a);
    f->son[!dir] = a->son[dir];
    f->son[!dir]->father = f;
    a->son[dir] = f;
    a->father = f->father;
    f->father->son[f->Check()] = a;
    f->father = a;
    PushUp(f);
    if(root == f)   root = a;
}
 
inline void Splay(Complex *a,Complex *aim)
{
    while(a->father != aim) {
        if(a->father->father == aim) 
            Rotate(a,!a->Check());
        else if(!a->father->Check()) {
            if(!a->Check()) {
                Rotate(a->father,true);
                Rotate(a,true);
            }
            else {
                Rotate(a,false);
                Rotate(a,true);
            }
        }
        else {
            if(a->Check()) {
                Rotate(a->father,false);
                Rotate(a,false);
            }
            else {
                Rotate(a,true);
                Rotate(a,false);
            }
        }
        PushUp(a);
    }
}
 
Complex *BuildTree(int l,int r)
{
    if(l > r)    return nil;
    int mid = (l + r) >> 1;
    Complex *now = NewComplex(temp[mid]);
    now->Combine(BuildTree(l,mid - 1),false);
    now->Combine(BuildTree(mid + 1,r),true);
    if(l != r)
        PushUp(now);
    return now;
}
 
void Delete(Complex *a)
{
    if(a == nil)    return ;
    Delete(a->son[0]),Delete(a->son[1]);
    free(a);
}
 
inline void SplaySeg(int st,int ed)
{
    st += 1,ed += 1;
    Splay(FindK(root,st - 1),nil);
    Splay(FindK(root,ed + 1),root);
}
 
Complex *FindK(Complex *a,int k)
{
    PushDown(a);
    if(k <= a->son[0]->size)
        return FindK(a->son[0],k);
    k -= a->son[0]->size;
    if(k == 1)  return a;
    --k;
    return FindK(a->son[1],k);
}
 
inline void PushDown(Complex *a)
{
    if(a == nil)    return ;
    if(a->change) {
        if(a->son[0] != nil)
            a->son[0]->Change(a->change_into);
        if(a->son[1] != nil)
            a->son[1]->Change(a->change_into);
        a->change = false;
    }
    if(a->reverse) {
        if(a->son[0] != nil)
            a->son[0]->Reverse();
        if(a->son[1] != nil)
            a->son[1]->Reverse();
        a->reverse = false;
    }
}
 
inline void PushUp(Complex *a)
{
    if(a == nil)    return ;
    a->size = a->son[0]->size + a->son[1]->size + 1;
    a->sum = a->son[0]->sum + a->son[1]->sum + a->val;
    a->l = max(a->son[0]->l,a->son[0]->sum + a->val + max(0,a->son[1]->l));
    a->r = max(a->son[1]->r,a->son[1]->sum + a->val + max(0,a->son[0]->r));
    a->all = max(max(a->son[0]->all,a->son[1]->all),a->val+max(0,a->son[0]->r)+max(0,a->son[1]->l));
}


奉上读入优化版本,因为有的OJ卡这个题的常数(比如我们学校自己的oj)

同学帮着写的,效率十分可观,BZOJ3472ms就过了


CODE(读入优化):


#include <cstdio>  
#include <cstring>  
#include <iostream>  
#include <algorithm> 
#include <cctype>

#define MAX 600010  
#define INF 0x7f7f7f7f  
using namespace std;  

inline int getc() {
    static const int L = 1 << 15;
    static char buf[L], *S = buf, *T = buf;
    if (S == T) {
        T = (S = buf) + fread(buf, 1, L, stdin);
        if (S == T)
            return EOF;
    }
    return *S++;
}
inline int getint() {
    int c;
    while(!isdigit(c = getc()) && c != '-');
    bool sign = c == '-';
    int tmp = sign ? 0 : c - '0';
    while(isdigit(c = getc()))
        tmp = (tmp << 1) + (tmp << 3) + c - '0';
    return sign ? -tmp : tmp;
}

struct Twochar {
    char c0, c1;
    Twochar(char _c0 = 0, char _c1 = 0):c0(_c0),c1(_c1){}
};
inline Twochar getch() {
    int c;
    while((c = getc()) != 'I' && c != 'D' && c != 'M' && c != 'R' && c != 'G');
    int c2 = getc();
    c2 = getc();
    if(c == 'I'&&c2=='S')getc(),getc(),getc();
    if(c == 'D'&&c2=='L')getc(),getc(),getc();
    if(c=='M'&&c2=='K')getc(),getc(),getc(),getc(),getc();
    if(c=='R'&&c2=='V')getc(),getc(),getc(),getc();
    if(c=='G'&&c2=='T')getc(),getc(),getc(),getc();
    if(c=='M'&&c2=='X')getc(),getc(),getc(),getc();
    return Twochar(c, c2);
} 

struct Complex{  
    int val,size;  
    bool change,reverse;  
    int change_into;  
    int sum;  
    int l,r,all;  
    Complex *son[2],*father;  
       
    bool Check() {  
        return father->son[1] == this;  
    }  
    void Combine(Complex *a,bool dir) {  
        son[dir] = a;  
        a->father = this;  
    }  
    void Reverse() {  
        reverse ^= 1;  
        swap(son[0],son[1]);  
        swap(l,r);  
    }  
    void Change(int x) {  
        val = x;  
        sum = x * size;  
        l = r = all = max(sum,val);  
        change = true;  
        change_into = x;  
    }  
}none,*nil = &none,*root = nil;  
   
void Pretreatment();  
inline Complex *NewComplex(int x);    
inline void Rotate(Complex *a,bool dir);  
inline void Splay(Complex *a,Complex *aim);  
Complex *BuildTree(int l,int r);  
inline void SplaySeg(int st,int ed);      
inline void PushUp(Complex *a);   
inline void PushDown(Complex *a);  
void Delete(Complex *a);  
Complex *FindK(Complex *a,int k);  
   
int cnt,asks;  
int pos,num;  
   
int temp[MAX];  
   
int main()  
{  
    cnt = getint();
    asks = getint();
    Pretreatment();  
    for(int i = 1;i <= cnt; ++i)   
        temp[i] = getint();
    root = BuildTree(0,cnt + 1);  
    root->father = nil; 

    Twochar s;
    for(int i = 1;i <= asks; ++i) {  
        s = getch();
        if(s.c0 == 'I' && s.c1 == 'S') {  
           pos=getint(),cnt=getint(),pos++;  
            for(int i = 1;i <= cnt; ++i)  
                temp[i]=getint();
            Splay(FindK(root,pos),nil);  
            Splay(FindK(root,pos + 1),root);  
            root->son[1]->Combine(BuildTree(1,cnt),false);  
            PushUp(root->son[1]),PushUp(root);  
        }  
        else if(s.c0 == 'D' && s.c1 == 'L') {  
            pos=getint(),cnt=getint();
            SplaySeg(pos,pos + cnt - 1);  
            Delete(root->son[1]->son[0]);  
            root->son[1]->son[0] = nil;  
            PushUp(root->son[1]),PushUp(root);  
        }  
        else if(s.c0 == 'M' && s.c1 == 'K') {  
            pos=getint(),cnt=getint(),num=getint();
            SplaySeg(pos,pos + cnt - 1);  
            root->son[1]->son[0]->Change(num);  
            PushUp(root->son[1]),PushUp(root);             
        }  
        else if(s.c0 == 'R' && s.c1 == 'V') {  
            pos=getint(),cnt=getint(); 
            SplaySeg(pos,pos + cnt - 1);  
            root->son[1]->son[0]->Reverse();  
            PushUp(root->son[1]),PushUp(root);             
        }  
        else if(s.c0 == 'G' && s.c1 == 'T') {  
            pos=getint(),cnt=getint(); 
            SplaySeg(pos,pos + cnt - 1);  
            printf("%d\n",root->son[1]->son[0]->sum);  
        }  
        else if(s.c0 == 'M' && s.c1 == 'X') {  
            int temp = root->size;  
            Splay(FindK(root,1),nil);  
            Splay(FindK(root,temp),root);  
            printf("%d\n",root->son[1]->son[0]->all);  
        }  
    }  
    return 0;  
}  
   
void Pretreatment()  
{  
    nil->son[0] = nil->son[1] = nil;  
    nil->father = nil;  
    nil->size = 0;  
    nil->all = -INF;  
    temp[0] = temp[cnt + 1] = -INF;  
}  
   
inline Complex *NewComplex(int x)  
{  
    Complex *re = new Complex();  
    re->son[0] = re->son[1] = nil;  
    re->size = 1;  
    re->sum = re->l = re->r = re->all = re->val = x;  
    re->change = re->reverse = false;  
    return re;  
}  
   
inline void Rotate(Complex *a,bool dir)  
{  
    Complex *f = a->father;  
    PushDown(f),PushDown(a);  
    f->son[!dir] = a->son[dir];  
    f->son[!dir]->father = f;  
    a->son[dir] = f;  
    a->father = f->father;  
    f->father->son[f->Check()] = a;  
    f->father = a;  
    PushUp(f);  
    if(root == f)   root = a;  
}  
   
inline void Splay(Complex *a,Complex *aim)  
{  
    while(a->father != aim) {  
        if(a->father->father == aim)   
            Rotate(a,!a->Check());  
        else if(!a->father->Check()) {  
            if(!a->Check()) {  
                Rotate(a->father,true);  
                Rotate(a,true);  
            }  
            else {  
                Rotate(a,false);  
                Rotate(a,true);  
            }  
        }  
        else {  
            if(a->Check()) {  
                Rotate(a->father,false);  
                Rotate(a,false);  
            }  
            else {  
                Rotate(a,true);  
                Rotate(a,false);  
            }  
        }  
    }
    PushUp(a);   
}  
   
Complex *BuildTree(int l,int r)  
{  
    if(l > r)    return nil;  
    int mid = (l + r) >> 1;  
    Complex *now = NewComplex(temp[mid]);  
    now->Combine(BuildTree(l,mid - 1),false);  
    now->Combine(BuildTree(mid + 1,r),true);  
    if(l != r)  
        PushUp(now);  
    return now;  
}  
   
void Delete(Complex *a)  
{  
    if(a == nil)    return ;  
    Delete(a->son[0]),Delete(a->son[1]);  
    free(a);  
}  
   
inline void SplaySeg(int st,int ed)  
{  
    st += 1,ed += 1;  
    Splay(FindK(root,st - 1),nil);  
    Splay(FindK(root,ed + 1),root);  
}  
   
Complex *FindK(Complex *a,int k)  
{  
    PushDown(a);  
    if(k <= a->son[0]->size)  
        return FindK(a->son[0],k);  
    k -= a->son[0]->size;  
    if(k == 1)  return a;  
    --k;  
    return FindK(a->son[1],k);  
}  
   
inline void PushDown(Complex *a)  
{  
    if(a == nil)    return ;  
    if(a->change) {  
        if(a->son[0] != nil)  
            a->son[0]->Change(a->change_into);  
        if(a->son[1] != nil)  
            a->son[1]->Change(a->change_into);  
        a->change = false;  
    }  
    if(a->reverse) {  
        if(a->son[0] != nil)  
            a->son[0]->Reverse();  
        if(a->son[1] != nil)  
            a->son[1]->Reverse();  
        a->reverse = false;  
    }  
}  
   
inline void PushUp(Complex *a)  
{  
    if(a == nil)    return ;  
    a->size = a->son[0]->size + a->son[1]->size + 1;  
    a->sum = a->son[0]->sum + a->son[1]->sum + a->val;  
    a->l = max(a->son[0]->l,a->son[0]->sum + a->val + max(0,a->son[1]->l));  
    a->r = max(a->son[1]->r,a->son[1]->sum + a->val + max(0,a->son[0]->r));  
    a->all = max(max(a->son[0]->all,a->son[1]->all),a->val+max(0,a->son[0]->r)+max(0,a->son[1]->l));  
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值