BZOJ1500 维修数列

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1500

[前言]

  据说没打这题就相当于没打过Splay,这题简直就是让你内心崩溃的...

  这题是一道综合味很强的题,初学者不要贸然尝试...先做些简单一点的[跟着笔者的步伐走...做一做3224、3223、1251、1014这种类型],最好也要有一定的线段树lazy_tag基础。

[分析]

  首先数据范围没写...但是前人告诉你必须要用Splay[写在source里了]

  所以说这题肯定有一个很大的数据范围...

  而这题中需要支持的操作大多是区间上的操作,也是有很多下传标记和求区间和与区间最值的,同时有翻转操作[似乎支持这些的也只有伸展树了...]。

  确定了总的方向,再具体看看操作:

  1.预处理出一开始给你的数列。[和平常一样构造就好,这个部分最需要注意的就是下标这种细节了]

  2.在一个位置后添加一段序列,和以前加一个数字的操作很像,但是我们要像之前处理初始序列一样将这棵子树先构造出来,再将根接到位置上。

  3.删除一段序列,以往的题,只需要将这棵子树与父节点的关系弄掉即可,这题因为点数要求多[每次删一段,加一段],所以还需要回收这些删除的点,具体方法[暴力一个个点的下去,把他们的编号放进墓地里]。

  4.修改一段序列为一个定值,和线段树的强制赋值一样处理就好了。

  5.翻转一段区间,翻转标记的处理,具体见BZOJ3223。

  6.求一段区间的和,每次上传的时候需要更新一下。

  7.求全局中的最大子串,这个稍稍难想一点。

  同样的因为上面的这种设置方法,我们在进行翻转操作的时候记得也要翻转lmax,rmax

  当然具体的细节问题,给你们自己去调试咯...

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

using namespace std;

inline int in(){
    int x=0,f=1;char ch=getchar();
    while((ch>'9' || ch<'0') && ch!='-') ch=getchar();
    if(ch=='-') f=-1,ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}

const int maxn=500010;
const int INF=0x3f3f3f3f;

struct Node{
    int ch[2],f;  //child[2],father
    int sz,dt,sm; //size,data,sum
    int lx,rx,mx; //left_max,right_max,Max
    
    bool rv,pt;      //rev,paint
}s[maxn];

int n,q,rt,tot1;
int st[maxn],tot2;//墓地和容量
int a[maxn];
char ch[15];

void NewNode(int &r,int father,int k){
    if(tot2) r=st[tot2--];//优先选择墓地里的
    else r=++tot1;
    s[r].f=father;
    s[r].ch[0]=s[r].ch[1]=0;
    s[r].dt=s[r].sm=k;
    s[r].rv=s[r].pt=0;
    s[r].lx=s[r].rx=s[r].mx=k;
    s[r].sz=1;
}

//应用并下传rev标记,记得要旋转左右最值
void Update_Rev(int x){
    if(!x) return;
    swap(s[x].ch[0],s[x].ch[1]);
    swap(s[x].lx,s[x].rx);
    s[x].rv^=1;
}

//应用并下传paint标记
void Update_Same(int x,int v){
    if(!x) return;
    s[x].dt=v;
    s[x].sm=v*s[x].sz;
    s[x].lx=s[x].rx=s[x].mx=max(v,v*s[x].sz);
    s[x].pt=1;
}

//更新节点信息
void push_up(int x){
    int l=s[x].ch[0],r=s[x].ch[1];
    s[x].sz=s[l].sz+s[r].sz+1;
    s[x].sm=s[l].sm+s[r].sm+s[x].dt;
    s[x].lx=max(s[l].lx,s[l].sm+s[x].dt+max(0,s[r].lx));
    s[x].rx=max(s[r].rx,s[r].sm+s[x].dt+max(0,s[l].rx));
    s[x].mx=max(0,s[l].rx)+s[x].dt+max(0,s[r].lx);
    s[x].mx=max(s[x].mx,max(s[l].mx,s[r].mx));
}

void push_down(int x){
    if(s[x].pt){
        Update_Same(s[x].ch[0],s[x].dt);
        Update_Same(s[x].ch[1],s[x].dt);
        s[x].pt=0;
    }
    if(s[x].rv){
        Update_Rev(s[x].ch[0]);
        Update_Rev(s[x].ch[1]);
        s[x].rv=0;
    }
}

void Build(int &x,int l,int r,int father){
    if(l>r) return;
    int mid=(l+r)>>1;
    NewNode(x,father,a[mid]);
    Build(s[x].ch[0],l,mid-1,x);
    Build(s[x].ch[1],mid+1,r,x);
    push_up(x);
}

void Init(){
    rt=tot1=tot2=0;
    s[rt].ch[0]=s[rt].ch[1]=s[rt].sz=s[rt].f=0;
    s[rt].pt=s[rt].rv=s[rt].sm=s[rt].dt=0;
    s[rt].lx=s[rt].rx=s[rt].mx=-INF;
    NewNode(rt,0,-1);
    NewNode(s[rt].ch[1],rt,-1);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    Build(s[s[rt].ch[1]].ch[0],0,n-1,s[rt].ch[1]);
    push_up(s[rt].ch[1]);
    push_up(rt);
}

void Rotate(int x,int k){
    int y=s[x].f;
    s[x].f=s[y].f;
    if(s[y].f){
        if(y==s[s[y].f].ch[0])
            s[s[y].f].ch[0]=x;
        else
            s[s[y].f].ch[1]=x;
    }
    s[y].ch[k]=s[x].ch[k^1];
    if(s[x].ch[k^1]) s[s[x].ch[k^1]].f=y;
    s[x].ch[k^1]=y;s[y].f=x;
    push_up(y),push_up(x);
}

void Splay(int x,int gf){
    int y;
    while(s[x].f!=gf){
        y=s[x].f;
        if(s[y].f==gf){
            if(x==s[y].ch[0]) Rotate(x,0); else Rotate(x,1);}
        else{
            int z=s[y].f;
            if(y==s[z].ch[0]){
                if(x==s[y].ch[0]) Rotate(y,0),Rotate(x,0); else Rotate(x,1),Rotate(x,0);}
            else{
                if(x==s[y].ch[1]) Rotate(y,1),Rotate(x,1); else Rotate(x,0),Rotate(x,1);}
        }
    }
    if(!gf) rt=x;
}

int Get_kth(int k){
    int p=rt;
    while(p){
        push_down(p);
        if(k<=s[s[p].ch[0]].sz) p=s[p].ch[0];
        else{
            k-=s[s[p].ch[0]].sz;
            if(k==1) return p;
            k--;p=s[p].ch[1];
        }
    }
}

//在第pos个数后面插入tot个数
void Insert(int pos,int tot){
    for(int i=0;i<tot;i++) scanf("%d",&a[i]);
    int x1=Get_kth(pos+1),x2=Get_kth(pos+2);
    Splay(x1,0),Splay(x2,x1);
    Build(s[x2].ch[0],0,tot-1,x2);
    push_up(x2),push_up(x1);
}

//删除子树
void erase(int x){
    if(!x) return; st[++tot2]=x;//删除的节点需要回收进墓地
    erase(s[x].ch[0]),erase(s[x].ch[1]);
}

//从第pos个数开始连续删除tot个数
void Delete(int pos,int tot){
    int x1=Get_kth(pos),x2=Get_kth(pos+tot+1);
    Splay(x1,0),Splay(x2,x1);
    erase(s[x2].ch[0]);
    s[s[x2].ch[0]].f=0;
    s[x2].ch[0]=0;
    push_up(x2),push_up(x1);
}

//将从第pos个数开始的连续的tot个数染色成c
void Make_Same(int pos,int tot,int c){
    int x1=Get_kth(pos),x2=Get_kth(pos+tot+1);
    Splay(x1,0),Splay(x2,x1);
    Update_Same(s[x2].ch[0],c);
    push_up(x2),push_up(x1);
}

//将第pos个数开始的连续tot个数进行反转
void Reverse(int pos,int tot){
    int x1=Get_kth(pos),x2=Get_kth(pos+tot+1);    
    Splay(x1,0),Splay(x2,x1);
    Update_Rev(s[x2].ch[0]);
    push_up(x2),push_up(x1);
}

//得到第pos个数开始的tot个数的和
int Get_Sum(int pos,int tot){
    int x1=Get_kth(pos),x2=Get_kth(pos+tot+1);
    Splay(x1,0),Splay(x2,x1);
    return s[s[x2].ch[0]].sm;
}

//得到第pos个数开始的tot个数中最大的子段和
int Get_MaxSum(int pos,int tot){
    int x1=Get_kth(pos),x2=Get_kth(pos+tot+1);
    Splay(x1,0),Splay(x2,x1);
    return s[s[x2].ch[0]].mx;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("1500.in","r",stdin);
    freopen("1500.out","w",stdout);
#endif
    int L,tot,x;
    
    n=in();q=in();
    Init();
    while(q--){
        scanf("%s",ch);
        if(ch[0]=='I')
            L=in(),tot=in(),Insert(L,tot);
        else if(ch[0]=='D')
            L=in(),tot=in(),Delete(L,tot);
        else if(ch[0]=='M'){
            if(ch[2]=='K')
                L=in(),tot=in(),x=in(),Make_Same(L,tot,x);
            else
                printf("%d\n",Get_MaxSum(1,s[rt].sz-2));
        }
        else if(ch[0]=='R')
            L=in(),tot=in(),Reverse(L,tot);
        else
            L=in(),tot=in(),printf("%d\n",Get_Sum(L,tot));
    }
    return 0;
}
View Code

 

posted @ 2015-12-28 21:30  诚叙  阅读(361)  评论(0编辑  收藏  举报