题目描述
请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)
输入输出格式
输入格式:
输入文件的第 1 行包含两个数 N 和 M,N 表示初始时数列中数的个数,M 表示要进行的操作数目。 第 2 行包含 N 个数字,描述初始时的数列。 以下 M 行,每行一条命令,格式参见问题描述中的表格
输出格式:
对于输入数据中的 GET-SUM 和 MAX-SUM 操作,向输出文件依次打印结 果,每个答案(数字)占一行。
SOL:
我们发现这是一道fhq_treap的模板题。
我们首先要会fhq_treap。(splay也可以)
我们发现一颗树无论如何旋转(或者split后merge),其中序遍历总是不变的(这是区间操作的基础)
如果我们按照想要的中序遍历建树并且合并,我们一定能得到正确的区间,所以平衡树的区间操作是正确的。
这也是平衡树的两大建立方式之一:按中序遍历建树(另外一种是按权值建树……就是最常见的那种)
这样就涉及到一个没有出现的函数:build(建树)函数。
我们可以暴力建树:(以洛谷p3391 文艺平衡树为例)
Treap* build(int l,int r){ if (l>r) return rr;//我们有#define rr NULL Treap *now=new Treap(0);//这里的值是可以改的,就是数组里的真实值 now->son[0]=build(l,MID-1);//递归处理 now->son[1]=build(MID+1,r); now->rub();//更新该节点的信息 return now; }
我们有2个懒标记 :flip,mark。
filp 是指指是不是被染成了同一种颜色,而mark标记是是否翻转。我们来看一下如何维护mark标记
void pushdown(Treap* x) { if (x && x->mark) { x->mark=0; swap(x->son[0],x->son[1]); if (x->son[0]) x->son[0]->mark^=1; if (x->son[1]) x->son[1]->mark^=1; } }
我们发现异常的简洁。这样我们就可以轻松的维护mark标记了。(这就是用平衡树的原因,线段树的话要维护的lazy标记便不是很方便(做法是维护一个一次函数作为lazy标记))
那么我们就只剩最后一个操作了:MAX—SUM,我们便可以维护一个区间的ls,rs,maxsum三个值:
ls是从左边起的极大序列 ,rs从右边起的极大序列 。maxsum是这个区间的最大值。
那么我们合并时,新区间的最大值只有2种情况:
1.最大值是两个子区间的最大值中的一个。
2.最大值是左区间的rs并上当前节点并上右区间的ls
那么我们就做完了。
不得不吐槽的是,由于常数和OJ评测速度的问题,我卡了2个小时的常,写出来了一些奇奇怪怪的东西:
正常版:(30MB,洛谷0.3S,本校OJ1.3S)(说多了都是泪)
#include<bits/stdc++.h> #define N 500007 #define MAXN 4000007 #define inf 0x3f3f3f3f #define MARICLE __attribute__((optimize("-O2"))) using namespace std; #define stack rrsb int n,a[N],point; #define sight(c) (‘0‘<=c&&c<=‘9‘) #define Sight(c) (‘A‘<=c&&c<=‘Z‘||c==‘-‘) #define abs(x) ((x)>0?(x):(-x)) #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) #define getchar nc inline char nc() { static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } MARICLE inline void read(int &x) { static char c; static int b; for (b=1,c=getchar(); !sight(c); c=getchar()) if (c==‘-‘) b=-1; for (x=0; sight(c); c=getchar()) x=x*10+c-48; x*=b; } MARICLE inline void reads(char* op) { static char c; static int b; for (b=0,c=getchar(); !Sight(c); c=getchar()); for (; Sight(c); c=getchar()) op[b++]=c; } struct Treap { Treap *ch[2]; int val,key,size,sum,l,r,m; bool flip,mark; MARICLE Treap() { /*val=l=r=m=-inf;sum=0;size=0;mark=flip=0;key=rand();*/ } MARICLE void re() { val=l=r=m=-inf; sum=0; size=0; mark=flip=0; key=rand(); } MARICLE inline void update() { size=ch[0]->size+ch[1]->size+1; sum=val+ch[0]->sum+ch[1]->sum; l=max(ch[0]->l,max(ch[0]->sum+val,ch[0]->sum+val+ch[1]->l)); r=max(ch[1]->r,max(val+ch[1]->sum,ch[0]->r+val+ch[1]->sum)); m=max(ch[0]->m,max(max(0,ch[0]->r)+val+max(0,ch[1]->l),ch[1]->m)); } }; Treap *null=new Treap(),*root=null,*stack[N],*x,*last; MARICLE inline void Maintain_flip(Treap *o) { if(o==null)return; o->flip^=1; swap(o->l,o->r); } MARICLE inline void Maintain_mark(Treap *o,int c) { if(o==null)return; o->val=c; o->sum=o->size*c; o->l=o->r=o->m=max(o->size*c,c); o->mark=1; } MARICLE inline void pushdown(Treap *o) { if(o==null)return; if(o->flip) { o->flip^=1; Maintain_flip(o->ch[0]); Maintain_flip(o->ch[1]); swap(o->ch[0],o->ch[1]); } if(o->mark) { Maintain_mark(o->ch[0],o->val); Maintain_mark(o->ch[1],o->val); o->mark=0; } } MARICLE inline Treap* newTreap(int val) { Treap *o=new Treap(); o->ch[1]=o->ch[0]=null; o->key=rand(); o->val=o->sum=val; o->size=1; o->flip=o->mark=0; o->m=o->l=o->r=val; return o; } MARICLE Treap *merge(Treap *a,Treap *b) { if(a==null)return b; if(b==null)return a; pushdown(a); pushdown(b); if(a->key < b->key) { a->ch[1]=merge(a->ch[1],b); a->update(); return a; } else { b->ch[0]=merge(a,b->ch[0]); b->update(); return b; } } MARICLE void split(Treap *now,int k,Treap* &x,Treap* &y) { if (now==null) { x=y=null; return; } pushdown(now); int cmp=now->ch[0]?now->ch[0]->size+1:1; if (k<cmp) y=now,split(y->ch[0],k,x,y->ch[0]); else x=now,split(x->ch[1],k-cmp,x->ch[1],y); now->update(); } int pos,c; MARICLE inline Treap *build() { int p=0; for(int i=1; i<=n; i++) { read(a[i]); x=newTreap(a[i]); last=null; while(p&&stack[p]->key > x->key) { stack[p]->update(); last=stack[p]; stack[p--]=null; } if(p)stack[p]->ch[1]=x; x->ch[0]=last; stack[++p]=x; } while(p)stack[p--]->update(); return stack[1]; } MARICLE void adjust(Treap *o) { if(o==null)return; if(o->ch[0]!=null)adjust(o->ch[0]); if(o->ch[1]!=null)adjust(o->ch[1]); delete o; } Treap* XX,*X,*Y,*Z; MARICLE inline void insert() { read(pos); read(n); Treap *o=build(); split(root,pos,X,Y); root=merge(merge(X,o),Y); } MARICLE inline void erase() { read(pos); read(n); split(root,pos-1,X,Y); split(Y,n,Y,Z); adjust(Y); root=merge(X,Z); } MARICLE inline void reverse() { read(pos); read(n); split(root,pos-1,X,Y); split(Y,n,Y,Z); Maintain_flip(Y); root=merge(merge(X,Y),Z); } MARICLE inline void make_same() { read(pos); read(n); read(c); split(root,pos-1,X,Y); split(Y,n,Y,Z); Maintain_mark(Y,c); root=merge(merge(X,Y),Z); } MARICLE inline int get_sum() { read(pos); read(n); if(n==0)return 0; split(root,pos-1,X,Y); split(Y,n,Y,Z); int ret=Y->sum; root=merge(merge(X,Y),Z); return ret; } int m; MARICLE void write(int x) { if (x<10) { putchar(‘0‘+x); return; } write(x/10); putchar(‘0‘+x%10); } MARICLE inline void writeln(int x) { if (x<0) putchar(‘-‘); write(abs(x)); putchar(‘\n‘); } MARICLE int main() { null->re(); read(n); read(m); root=build(); char opt[15]; while(m--) { reads(opt); // scanf("%s",opt); switch(opt[0]) { case ‘I‘: insert(); break; case ‘D‘: erase(); break; case ‘M‘: if (opt[2]!=‘K‘) writeln(root->m); else make_same(); break; case ‘G‘: writeln(get_sum()); break; case ‘R‘: reverse(); break; } } }
我注意到我校的OJ空间开了128MB,便选择了随机删点。外加惨无人道的压代码,就写成了这样:
#include<bits/stdc++.h> #define N 500007 #define inf 0x3f3f3f3f #define MARICLE __attribute__((optimize("-O2"))) #define MARICL __attribute__((optimize("-O3"))) using namespace std; #define stack rrsb int n,a[N],point,ret;char opt[15];int pos,c,p,m; #define sight(c) (‘0‘<=c&&c<=‘9‘) #define Sight(c) (‘A‘<=c&&c<=‘Z‘||c==‘-‘) #define abs(x) ((x)>0?(x):(-x)) #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) #define getchar nc #define rand org MARICL inline int org(){ static int x=5438;return x^=x<<13,x^=x>>17,x^=x<<5;} MARICL inline char nc(){static char buf[500000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,500000,stdin),p1==p2)?EOF:*p1++;} MARICL inline void read(int &x) {static char c; static int b;for (b=1,c=getchar();!sight(c);c=getchar()) if (c==‘-‘) b=-1;for (x=0;sight(c);c=getchar()) x=x*10+c-48;x*=b;} MARICL inline void reads(char* op) {static char c; static int b; for (b=0,c=getchar();!Sight(c);c=getchar());for (;Sight(c);c=getchar()) op[b++]=c;} struct Treap{ Treap *ch[2];int val,key,size,sum,l,r,m;bool flip,mark;MARICL Treap(){}MARICL void re() {val=l=r=m=-inf;sum=0;size=0;mark=flip=0;key=rand();}MARICL inline void update(){ size=ch[0]->size+ch[1]->size+1;sum=val+ch[0]->sum+ch[1]->sum;l=max(ch[0]->l,max(ch[0]->sum+val,ch[0]->sum+val+ch[1]->l));r=max(ch[1]->r,max(val+ch[1]->sum,ch[0]->r+val+ch[1]->sum));m=max(ch[0]->m,max(max(0,ch[0]->r)+val+max(0,ch[1]->l),ch[1]->m));}}; Treap *null=new Treap(),*root=null,*stack[N],*x,*last;Treap* XX,*X,*Y,*Z; MARICL inline void Maintain_flip(Treap *o){ if(o==null)return;o->flip^=1;swap(o->l,o->r);} MARICL inline void Maintain_mark(Treap *o,int c){if(o==null)return;o->val=c;o->sum=o->size*c;o->l=o->r=o->m=max(o->size*c,c);o->mark=1;} MARICL inline void pushdown(Treap *o){if(o==null)return;if(o->flip) {o->flip^=1; Maintain_flip(o->ch[0]); Maintain_flip(o->ch[1]); swap(o->ch[0],o->ch[1]);}if(o->mark) { Maintain_mark(o->ch[0],o->val); Maintain_mark(o->ch[1],o->val);o->mark=0;}} MARICL inline Treap* newTreap(int val){Treap *o=new Treap(); o->ch[1]=o->ch[0]=null;o->key=rand(); o->val=o->sum=val;o->size=1;o->flip=o->mark=0;o->m=o->l=o->r=val;return o;} MARICLE Treap *merge(Treap *a,Treap *b){ if(a==null)return b; if(b==null)return a;pushdown(a);pushdown(b);if(a->key < b->key) {a->ch[1]=merge(a->ch[1],b);a->update();return a;}else {b->ch[0]=merge(a,b->ch[0]);b->update();return b;}} MARICL void split(Treap *now,int k,Treap* &x,Treap* &y){if (now==null) {x=y=null;return;}pushdown(now);int cmp=now->ch[0]?now->ch[0]->size+1:1;if (k<cmp) y=now,split(y->ch[0],k,x,y->ch[0]);else x=now,split(x->ch[1],k-cmp,x->ch[1],y);now->update();} MARICL inline Treap *build(){for(int i=1;i<=n;i++){read(a[i]);x=newTreap(a[i]);last=null;while(p&&stack[p]->key > x->key){stack[p]->update();last=stack[p];stack[p--]=null;}if(p)stack[p]->ch[1]=x;x->ch[0]=last;stack[++p]=x;}while(p)stack[p--]->update();return stack[1];} MARICL void adjust(Treap *o){if(o==null)return;if (!(rand()&15))return;if(o->ch[0]!=null)adjust(o->ch[0]);if(o->ch[1]!=null)adjust(o->ch[1]);delete o;} MARICL inline void insert(){read(pos); read(n);Treap *o=build();split(root,pos,X,Y);root=merge(merge(X,o),Y);} MARICL inline void erase(){ read(pos); read(n);split(root,pos-1,X,Y);split(Y,n,Y,Z);adjust(Y);root=merge(X,Z);} MARICL inline void reverse(){ read(pos); read(n);split(root,pos-1,X,Y);split(Y,n,Y,Z);Maintain_flip(Y);root=merge(merge(X,Y),Z);} MARICL inline void make_same(){read(pos); read(n); read(c);split(root,pos-1,X,Y);split(Y,n,Y,Z);Maintain_mark(Y,c);root=merge(merge(X,Y),Z);} MARICL inline int get_sum(){ read(pos); read(n);if(n==0)return 0;split(root,pos-1,X,Y);split(Y,n,Y,Z);ret=Y->sum;root=merge(merge(X,Y),Z);return ret;} MARICLE void write(int x){if (x<10) {putchar(‘0‘+x);return;} write(x/10); putchar(‘0‘+x%10);} MARICLE inline void writeln(int x){if (x<0) putchar(‘-‘); write(abs(x)); putchar(‘\n‘);} MARICL int main(){null->re();read(n);read(m);root=build();while(m--){ reads(opt);switch(opt[0]){ case ‘I‘:insert();break;case ‘D‘:erase();break;case ‘M‘:if (opt[2]!=‘K‘) writeln(root->m); else make_same(); break;case ‘G‘:writeln(get_sum());break;case ‘R‘:reverse();break;}}}
代码丑不要打我。。。