码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1500 NOI 2005 维修数列 Splay

时间:2014-09-06 09:48:03      阅读:242      评论:0      收藏:0      [点我收藏+]

标签:splay tree   平衡树   noi2005   数据结构   维修数列   

题意:见下图

bubuko.com,布布扣


传说级别的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));
}


BZOJ 1500 NOI 2005 维修数列 Splay

标签:splay tree   平衡树   noi2005   数据结构   维修数列   

原文地址:http://blog.csdn.net/jiangyuze831/article/details/39098481

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!