bzoj1500 [NOI2005]维修数列

Posted liu_runda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1500 [NOI2005]维修数列相关的知识,希望对你有一定的参考价值。

坑点:GET-SUM的第二个参数可以是0,这时直接输出0.(论1A和差点1A的区别)(没事反正这次是在cogs上交的我下次重写一遍bzoj上一定能1A)

最大子段和的处理需要对每棵子树维护一下最大前缀和,最大后缀和以及最大子段和(都不能为空)。把这些数据打包写成一个结构体就比较整洁了。

每个子树的数据=左子树+根节点+右子树,数据打包之后这两个‘+’本质是相同的操作。

然后就都是套路了,split一下,merge一下。。。

#include<cstdio>
#include<algorithm>
using namespace std;
struct data{
  int lmax,rmax,mmax,sum;
  void rev(){
    swap(lmax,rmax);
  }
  data(){}
  data(int x){lmax=rmax=sum=mmax=x;}
  data(int x,int num){
    sum=x*num;
    lmax=rmax=mmax=max(x,sum);
  }
  data operator +(const data &B)const{
    data C;
    C.sum=sum+B.sum;
    C.lmax=max(lmax,sum+B.lmax);C.rmax=max(B.rmax,B.sum+rmax);
    C.mmax=max(max(mmax,B.mmax),rmax+B.lmax);
    return C;
  }
};
const int maxn=500005;
struct node{
  int mk,mkt;//mkt==2:change mkt==1:reverse mkt==0:nothing
  data subtree,rtnode;
  node* ch[2],*prt;
  int sz;
  node(){}
  node(int x,node* p){
    ch[0]=ch[1]=0;prt=p;mk=mkt=0;
    subtree=rtnode=data(x);
  }
  void setto(int x){
    mkt=2;mk=x;rtnode=data(x);subtree=data(x,sz);
  }
  void rev(){
    if(mkt==2)return;
    mkt^=1;subtree.rev();
  }
  void update(){
    subtree=rtnode;sz=1;
    if(ch[0])subtree=ch[0]->subtree+subtree,sz+=ch[0]->sz;
    if(ch[1])subtree=subtree+ch[1]->subtree,sz+=ch[1]->sz;
  }
  void pushdown(){
    if(mkt==1){
      swap(ch[0],ch[1]);
      if(ch[0])ch[0]->rev();if(ch[1])ch[1]->rev();
      mkt=0;
    }else if(mkt==2){
      if(ch[0])ch[0]->setto(mk);if(ch[1])ch[1]->setto(mk);
      mkt=0;
    }
  }
};
node *root,*c0,*c1;
node *kth(node *rt,int k){
  rt->pushdown();
  int lsz=(rt->ch[0])?rt->ch[0]->sz:0;
  if(k<=lsz)return kth(rt->ch[0],k);
  if(k==lsz+1)return rt;
  return kth(rt->ch[1],k-lsz-1);
}
inline int isch1(node *rt){return rt==(rt->prt->ch[1]);}
void rot(node *rt,int t){
  node *c=rt->ch[t],*p=rt->prt;
  rt->pushdown();c->pushdown();
  if(!p)root=c;
  else p->ch[isch1(rt)]=c;
  c->prt=p;
  rt->ch[t]=c->ch[t^1];
  if(c->ch[t^1])c->ch[t^1]->prt=rt;
  rt->prt=c;c->ch[t^1]=rt;
  rt->update();c->update();
}
void splay(node* rt,node *ed){
  node *p,*g;
  while((p=rt->prt)&&(g=p->prt)){
    g->pushdown();p->pushdown();
    if(p==ed)return;
    if(g==ed){rot(p,isch1(rt));return;}
    int t1=isch1(rt),t2=isch1(p);
    if(t1==t2){rot(g,t2);rot(p,t1);}
    else {rot(p,t1);rot(g,t2);}
  }
  if(ed==0&&p!=0){p->pushdown();rot(p,isch1(rt));}
}
void split(int l,int r){
  splay(kth(root,l),0);
  c0=root->ch[0];
  if(c0){c0->prt=0;root->ch[0]=0;root->update();}
  splay(kth(root,r-l+1),0);
  c1=root->ch[1];
  if(c1){c1->prt=0;root->ch[1]=0;root->update();}
}
void split(int l){
  if(l==0){
    c1=root;c0=0;root=0;return;
  }
  splay(kth(root,l),0);
  c1=root->ch[1];
  if(c1){c1->prt=0;root->ch[1]=0;root->update();}
  c0=root;root=0;
}
void merge3(){
  splay(kth(root,1),0);root->ch[0]=c0;
  if(c0){c0->prt=root;root->update();}
  splay(kth(root,root->sz),0);root->ch[1]=c1;
  if(c1){c1->prt=root;root->update();}
}
void merge2(){
  if(!c1)root=c0;
  else if(!c0)root=c1;
  else{
    root=c1;splay(kth(root,1),0);root->ch[0]=c0;c0->prt=root;root->update();
  }
}
void remove(int l,int r){
  split(l,r);merge2();
}
void reverse(int l,int r){
  split(l,r);root->rev();root->pushdown();merge3();
}
void change(int l,int r,int x){
  split(l,r);root->setto(x);root->pushdown();merge3();
}
void getsum(int l,int r){
  if(l>r){printf("0\n");return;}
  split(l,r);printf("%d\n",root->subtree.sum);merge3();
}
void maxsum(){printf("%d\n",root->subtree.mmax);}
int seq[maxn];
void build(node* &rt,node *p,int l,int r){
  if(l>r)return;
  int mid=(l+r)>>1;
  rt=new node(seq[mid],p);
  build(rt->ch[0],rt,l,mid-1);build(rt->ch[1],rt,mid+1,r);
  rt->update();
}
void insert(int pos,int len){
  split(pos);build(root,0,1,len);merge3();
}
int main(){
//  freopen("seq2005.in","r",stdin);
//  freopen("seq2005.out","w",stdout);
  int n,m;scanf("%d%d",&n,&m);
  for(int i=1;i<=n;++i)scanf("%d",seq+i);
  build(root,0,1,n);
  char buf[20];
  int x,y,z;
  for(int i=1;i<=m;++i){
    scanf("%s",buf);
    if(buf[0]==I){
      scanf("%d%d",&x,&y);
      for(int i=1;i<=y;++i)scanf("%d",seq+i);
      insert(x,y);
    }else if(buf[0]==D){
      scanf("%d%d",&x,&y);remove(x,x+y-1);
    }else if(buf[0]==G){
      scanf("%d%d",&x,&y);getsum(x,x+y-1);
    }else if(buf[0]==R){
      scanf("%d%d",&x,&y);reverse(x,x+y-1);
    }else if(buf[2]==X){
      maxsum();
    }else {
      scanf("%d%d%d",&x,&y,&z);change(x,x+y-1,z);
    }
  }
//  fclose(stdin);fclose(stdout);
  return 0;
}

 

以上是关于bzoj1500 [NOI2005]维修数列的主要内容,如果未能解决你的问题,请参考以下文章

bzoj:1500: [NOI2005]维修数列

BZOJ1500: [NOI2005]维修数列[splay ***]

BZOJ1500[NOI2005]维修数列

BZOJ1500: [NOI2005]维修数列

bzoj1500 [NOI2005]维修数列

bzoj1500: [NOI2005]维修数列