[bzoj1500][NOI2005 维修数列] (splay区间操作)

Description

Input

输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目。
第2行包含N个数字,描述初始时的数列。
以下M行,每行一条命令,格式参见问题描述中的表格。
任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内。
插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

HINT

Solution

#include<cstdio>
#include<iostream>
#define N 500010
#define inf 0x3f3f3f3f
#define mid ((x>>1)+(y>>1)+(x&y&1))
using namespace std;
inline int Rin(){
  int x=0,c=getchar(),f=1;
  for(;c<48||c>57;c=getchar())
    if(!(c^45))f=-1;
  for(;c>47&&c<58;c=getchar())
    x=(x<<1)+(x<<3)+c-48;
  return x*f;
}
struct nt{
  nt*ch[2],*p;
  bool rev;int cov;
  int size,sum,v,lmx,rmx,mmx;
  bool d(){return this==p->ch[1];}
  void setc(nt*c,int d){
    ch[d]=c;
    c->p=this;
  }
  void revIt(){
    rev^=1;
    swap(lmx,rmx);
    swap(ch[0],ch[1]);
  }
  void covIt(int co){
    cov=v=co;
    sum=co*size;
    co>0?lmx=rmx=mmx=sum:
    lmx=rmx=mmx=co;
  }
  void pu(){
    size=1+ch[0]->size+ch[1]->size;
    sum=v+ch[0]->sum+ch[1]->sum;
    lmx=max(ch[0]->lmx,ch[0]->sum+v+max(ch[1]->lmx,0));
    rmx=max(ch[1]->rmx,ch[1]->sum+v+max(ch[0]->rmx,0));
    mmx=max(max(ch[0]->mmx,ch[1]->mmx),max(ch[0]->rmx,0)+v+max(ch[1]->lmx,0));
  }
  void relax(){
    if(rev)
      ch[0]->revIt(),
    ch[1]->revIt();
    if(cov^inf)
      ch[0]->covIt(cov),
    ch[1]->covIt(cov);
    rev=0;
    cov=inf;
  }
};
nt*null=new nt();
nt*root=null;
int n,a[N],m;
char sign[10];
nt*newnode(nt*p,int v){
  nt*o=new nt();
  o->size=1;
  o->v=o->sum=o->lmx=o->rmx=o->mmx=v;
  o->ch[0]=o->ch[1]=null;
  o->cov=inf;
  o->p=p;
  return o;
}
void rot(nt*&o){
  nt*p=o->p;
  p->relax();
  o->relax();
  bool d=o->d();
  p->p->setc(o,p->d());
  p->setc(o->ch[!d],d);
  o->setc(p,!d);
  p->pu();o->pu();
  if(p==root)root=o;
}
void splay(nt*o,nt*p){
  while(o->p!=p)
    if(o->p->p==p)
      rot(o);
    else
      o->d()^o->p->d()?(rot(o),rot(o)):(rot(o->p),rot(o));
  o->pu();
}
nt*build(int x,int y){
  if(x>y)return null;
  nt*o=newnode(o,a[mid]);
  o->setc(build(x,mid-1),0);
  o->setc(build(mid+1,y),1);
  o->pu();
  return o;
}
void del(nt*&o){
  if(o->ch[0]!=null)del(o->ch[0]);
  if(o->ch[1]!=null)del(o->ch[1]);
  delete o;
}
nt*kth(int k){
  for(nt*o=root;;){
    o->relax();
    if(k<=o->ch[0]->size)
      o=o->ch[0];
    else{
      k-=o->ch[0]->size+1;
      if(!k)return o;
      o=o->ch[1];
    }
  }
}
int main(){
  n=Rin(),m=Rin();
  for(int i=1;i<=n;i++)a[i]=Rin();
  root=build(0,n+1);
  root->p=null;
  int x,y,z;
  while(m--){
    scanf("%s",sign);
    switch(sign[2]){
    case‘S‘:
      x=Rin(),y=Rin();
      for(int i=1;i<=y;i++)a[i]=Rin();
      splay(kth(x+1),null);
      splay(kth(x+2),root);
      root->ch[1]->setc(build(1,y),0);
      root->ch[1]->pu();
      root->pu();
      break;
    case‘L‘:
      x=Rin(),y=Rin();
      splay(kth(x),null);
      splay(kth(x+y+1),root);
      del(root->ch[1]->ch[0]);
      root->ch[1]->ch[0]=null;
      root->ch[1]->pu();
      root->pu();
      break;
    case‘K‘:
      x=Rin(),y=Rin(),z=Rin();
      splay(kth(x),null);
      splay(kth(x+y+1),root);
      root->ch[1]->ch[0]->covIt(z);
      root->ch[1]->pu();
      root->pu();
      break;
    case‘T‘:
      x=Rin(),y=Rin();
      splay(kth(x),null);
      splay(kth(x+y+1),root);
      printf("%d\n",root->ch[1]->ch[0]->sum);
      break;
    case‘V‘:
      x=Rin(),y=Rin();
      splay(kth(x),null);
      splay(kth(x+y+1),root);
      root->ch[1]->ch[0]->revIt();
      root->ch[1]->pu();
      root->pu();
      break;
    case‘X‘:
      splay(kth(1),null);
      splay(kth(root->size),root);
      printf("%d\n",root->ch[1]->ch[0]->mmx);
      break;
    default:break;
    }
  }
  return 0;
}
时间: 2024-08-01 22:59:39

[bzoj1500][NOI2005 维修数列] (splay区间操作)的相关文章

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

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12278  Solved: 3880[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

BZOJ 1500: [NOI2005]维修数列( splay )

splay..... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #define rep( i , n ) for( int i = 0 ; i < n ; ++

BZOJ1500 NOI2005 维修数列 平衡树

题意:给定一个数列,要求维护:1.在p之后加入tot个数  2.删除p之后tot个数  3.将p之后tot个数修改为c  4.翻转p之后tot个数  5.输出p之后tot个数的和  6.输出整个数列的最大子段和. 题解:平衡树很经典的题目了……主要说一下4和6操作,4的话因为翻转操作是可以分治的,所以可以用翻转标记:6我们维护一个节点所维护的区间的的最大子段和ms.从左开始的最大子段和lms.从右开始的最大子段和rms,显然有ms=max(lchild->ms,rchild->ms,lchil

【bzoj1500】维修数列——splay

splay的高级题目,有splay的全部操作,然而本蒟蒻竟不自量力地把这道题作为splay的入门题,然后就学(mi)习(man)了一个星期-- 第一次是对着cyc的模版码的,万分感谢>< 第二次就自己码了一个小时(弱......) 就作为一个splay学习的模版吧! #include<cstdio> #include<cstring> #include<iostream> #include<queue> const int maxn=5e5+10

HYSBZ 1500 [NOI2005]维修数列 splay

解题思路:终于把这道splay神题A掉了,splay专题也算是告一段落了,这个题主要的坑点,还是旋转和区间合并结合. 解题代码: 1 // File Name: hysbz1500.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月10日 星期五 10时41分03秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set>

[BZOJ1500]NOI2005 维护数列|splay

这题号称是noi出过最变态的数据结构题,,感觉还差不多嘛..一开始我一直在纠结splay上的节点一点要有一个key值的啊,要是以这个数在序列中的位置作为key值的话又要插入又要删除肯定弄不了..然后想了很久突然顿悟..貌似我给一个初始顺序以后是不用访问key的&&找第k位的数只要写一个findkth就行了嘛..(当时太弱) 然后我就一口气写了下来.. 对每个节点维护size,sum,maxsum,maxpre,maxpos(这两个用于更新maxsum),same,rev(这两个是lazy标

bzoj1500: [NOI2005]维修数列

splay. 就是splay,没别的了. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 600000 + 10; const int inf = 0x3f3f3f3f; struct Splay { int v[maxn],s[maxn],sum[maxn]; int l[maxn],r[maxn],f[maxn]; int max

Splay必做题 [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6577  Solved: 1978[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印

bzoj1500 维修数列 splay

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 10482  Solved: 3234[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,