[NOI2005]维护数列
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
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
10
1
10
HINT
题解:
听说做了这道题splay就差不多过关了。(然而我调了一天)
关于问题中的几个操作:
1.插入
将输入的数列用建二叉树的方式建成一棵splay,然后将目标位置的那个节点旋转到根,再将后面那个节点旋转到根的下方(就是split操作),然后就直接将新的splay接到根节点的右子节点的左子节点上。
2.删除
也是像之前一样,用split操作将删除的区间确定在根节点的右子节点的左子节点处,然后将删除的区间加入内存池就好了。
3.修改
先split一下,然后在根节点的右子节点的左子节点打上修改标记。
4.旋转
先split一下,然后在根节点的右子节点的左子节点打上旋转标记。
5.求和
先split一下,直接输出根节点右子节点的左子节点的sum。
6.求和最大的子列
就像线段树维护一样,对于每一个节点,我们令它所控制的区间是以它为根节点子树,然后维护三个参数ls,rs,ms。分别表示这个区间左边最大的子列,右边最大的子列,中间最大的子列。然后每次push_up的时候跟新一下就好。
当然这道题目很折磨人,有很多细节:
1.splay维护区间的时候要在一头一尾加上一个极值,因为如果不加,find可能会找不到
2.输出和最大的子列的时候也是需要split的,因为两端的极值会对根节点的三个参数造成影响。
3.push_up和push_down中维护ls,rs,ms的部分有些地方要和0取max,详见代码。
4.在find中push_down(这个是套路)
1 //Never forget why you start 2 #include<iostream> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<cstring> 6 #include<cmath> 7 #include<algorithm> 8 #include<queue> 9 #define inf (0x3f3f3f3f) 10 #define ll(x) bst[x].child[0] 11 #define rr(x) bst[x].child[1] 12 #define son(x,t) bst[x].child[t] 13 using namespace std; 14 int n,m,cnt; 15 int pos[1000005],root,a[1000005]; 16 struct Bst{ 17 int child[2],fa,size,sum,x,lazy,round,ls,rs,ms,islazy; 18 }bst[1000005]; 19 queue<int>mem; 20 void push_up(int rt){ 21 int l=ll(rt),r=rr(rt); 22 bst[rt].sum=bst[l].sum+bst[r].sum+bst[rt].x; 23 bst[rt].size=bst[l].size+bst[r].size+1; 24 bst[rt].ls=bst[rt].rs=bst[rt].ms=-inf; 25 bst[rt].ms=max(max(0,bst[l].rs)+bst[rt].x+max(0,bst[r].ls),max(bst[l].ms,bst[r].ms)); 26 bst[rt].rs=max(bst[r].rs,bst[r].sum+bst[rt].x+max(0,bst[l].rs)); 27 bst[rt].ls=max(bst[l].ls,bst[l].sum+bst[rt].x+max(0,bst[r].ls)); 28 } 29 void rotate(int r,int t){ 30 int fa=bst[r].fa; 31 son(fa,!t)=son(r,t);bst[son(r,t)].fa=fa; 32 son(bst[fa].fa,son(bst[fa].fa,1)==fa)=r;bst[r].fa=bst[fa].fa; 33 son(r,t)=fa;bst[fa].fa=r; 34 push_up(fa); 35 push_up(r); 36 } 37 void splay(int r,int goal){ 38 int fa=bst[r].fa; 39 while(fa!=goal){ 40 if(bst[fa].fa==goal)rotate(r,son(fa,0)==r); 41 else{ 42 int t=son(bst[fa].fa,0)==fa; 43 if(son(fa,t)==r)rotate(r,!t),rotate(r,t); 44 else rotate(fa,t),rotate(r,t); 45 } 46 fa=bst[r].fa; 47 } 48 if(goal==0)root=r; 49 } 50 void push_down(int root){ 51 int l=son(root,0),r=son(root,1); 52 if(bst[root].round){ 53 bst[l].round^=1;bst[r].round^=1; 54 swap(son(root,0),son(root,1)); 55 swap(bst[l].ls,bst[l].rs); 56 swap(bst[r].ls,bst[r].rs); 57 bst[root].round=0; 58 } 59 if(bst[root].islazy){ 60 if(l)bst[l].islazy=1,bst[l].lazy=bst[root].x,bst[l].x=bst[root].x,bst[l].sum=bst[l].size*bst[root].x; 61 if(r)bst[r].islazy=1,bst[r].lazy=bst[root].x,bst[r].x=bst[root].x,bst[r].sum=bst[r].size*bst[root].x; 62 if(bst[root].lazy>=0){ 63 bst[l].ls=bst[l].rs=bst[l].ms=bst[l].sum; 64 bst[r].ls=bst[r].rs=bst[r].ms=bst[r].sum; 65 } 66 else{ 67 bst[l].ls=bst[l].rs=bst[l].ms=bst[root].x; 68 bst[r].ls=bst[r].rs=bst[r].ms=bst[root].x; 69 } 70 bst[root].lazy=0; 71 bst[root].islazy=0; 72 } 73 } 74 int find(int r,int k){ 75 push_down(r); 76 int y=bst[son(r,0)].size; 77 if(y+1==k)return r; 78 else if(y>=k)return find(ll(r),k); 79 else return find(rr(r),k-y-1); 80 } 81 int newnode(){ 82 int pos; 83 if(!mem.empty())pos=mem.front(),mem.pop(); 84 else pos=++cnt; 85 bst[pos].child[0]=bst[pos].child[1]=bst[pos].fa=0; 86 bst[pos].islazy=bst[pos].lazy=bst[pos].round=0; 87 bst[pos].rs=bst[pos].ls=bst[pos].ms=-inf; 88 bst[pos].sum=bst[pos].x=0; 89 bst[pos].size=1; 90 return pos; 91 } 92 void build(int l,int r,int fa,int f){ 93 int mid=(l+r)>>1,now=pos[mid]=newnode(); 94 if(l==r){ 95 bst[now].sum=bst[now].x=a[l]; 96 bst[now].ls=bst[now].rs=bst[now].ms=a[l]; 97 } 98 if(l<mid)build(l,mid-1,now,mid); 99 if(mid<r)build(mid+1,r,now,mid); 100 bst[now].x=a[mid];bst[now].fa=fa; 101 push_up(now); 102 son(fa,mid>=f)=now; 103 } 104 void insert(int place,int tot){ 105 int i; 106 for(i=1;i<=tot;i++) 107 scanf("%d",&a[i]); 108 build(1,tot,0,0); 109 int rt=pos[(tot+1)>>1],x=find(root,place),y=find(root,place+1); 110 splay(x,0);splay(y,x); 111 son(y,0)=rt;bst[rt].fa=y; 112 push_up(y); 113 push_up(x); 114 } 115 void clean(int r){ 116 if(r){ 117 mem.push(r); 118 clean(son(r,0)); 119 clean(son(r,1)); 120 } 121 } 122 void delet(int place,int tot){ 123 int x=find(root,place-1),y=find(root,place+tot); 124 splay(x,0);splay(y,x); 125 clean(son(y,0)); 126 son(y,0)=0; 127 push_up(y);push_up(x); 128 } 129 void make_same(int place,int tot,int c){ 130 int x=find(root,place-1),y=find(root,place+tot); 131 splay(x,0);splay(y,x); 132 int z=son(y,0); 133 bst[z].sum=c*bst[z].size; 134 bst[z].lazy=c; 135 bst[z].islazy=1; 136 bst[z].x=c; 137 if(c>=0){ 138 bst[z].ls=bst[z].rs=bst[z].ms=c*bst[z].size; 139 } 140 else{ 141 bst[z].ls=bst[z].rs=bst[z].ms=c; 142 } 143 push_up(y);push_up(x); 144 } 145 void rever(int place,int tot){ 146 int x=find(root,place-1),y=find(root,place+tot); 147 splay(x,0);splay(y,x); 148 int z=son(y,0); 149 bst[z].round^=1; 150 swap(bst[z].ls,bst[z].rs); 151 push_up(y);push_up(x); 152 } 153 int get_sum(int place,int tot){ 154 int x=find(root,place-1),y=find(root,place+tot); 155 splay(x,0);splay(y,x); 156 return bst[son(y,0)].sum; 157 } 158 int max_sum(){ 159 int x=find(root,1),y=find(root,bst[root].size); 160 splay(x,0);splay(y,x); 161 return bst[son(y,0)].ms; 162 } 163 int main(){ 164 int i,j; 165 scanf("%d%d",&n,&m); 166 a[1]=-inf;a[n+2]=-inf; 167 for(i=1;i<=n;i++) 168 scanf("%d",&a[i+1]); 169 n+=2; 170 build(1,n,0,0); 171 root=pos[(1+n)>>1]; 172 for(i=1;i<=m;i++){ 173 char s[10];int place,tot,c; 174 scanf("%s",s); 175 if(s[0]=='I')scanf("%d%d",&place,&tot),insert(place+1,tot); 176 if(s[0]=='D')scanf("%d%d",&place,&tot),delet(place+1,tot); 177 if(s[0]=='M'&&s[2]=='K')scanf("%d%d%d",&place,&tot,&c),make_same(place+1,tot,c); 178 if(s[0]=='R')scanf("%d%d",&place,&tot),rever(place+1,tot); 179 if(s[0]=='G')scanf("%d%d",&place,&tot),printf("%d\n",get_sum(place+1,tot)); 180 if(s[0]=='M'&&s[2]=='X')printf("%d\n",max_sum()); 181 } 182 return 0; 183 }