可持久化(非旋转式)treap 学习记录
2015-01-18 16:59
232 查看
在做完郁闷的出纳员、宠物收养所等题之后,COGS上本蒟蒻和Rivendell神再也没有找到纯旋转式treap可以做的题,要么是区间类问题,要么就是各种树套树。。。
于是决定学一些解决区间问题的平衡树方法,按理说应当学splay,但莫名其妙地学上了非旋转式treap,我也是呵呵了。。。
介绍一下原理,原来的treap是通过左旋右旋来维护最小堆性质,但在此处,由于是区间操作,我们需要截出一整段区间(也就是一段treap),并且在重新插入回去的时候,不能够破坏最小堆性质,于是我们可以用merge(合并操作,注意:此处的merge操作与旋转式treap的merge并不相同)和split(拆分操作)来维护,具体做法是:
1、把某数插入到第k个位置:用split把treap拆分为前k-1位和后size-k+1位,然后以此节点的value新建立一个节点,依次将这三部分merge起来就好了。
2、把某数从第k个位置删除:同样,先用split把treap拆分为和后size-k+1位,再把后size-k+1位拆分为第k位和后size-k+2位,在将前k-1位和后size-k+2位merge起来就好了。
3、翻转,平移,求和,修改值等操作几乎都是把所需区间截取出来,特别注意的是翻转、修改值等操作需要懒惰标记,方法与线段树大同小异。
。。。。。。上习题
POJ 3580 SuperMemo
非旋转式treap第一题(我在Rivendell神的带领下,上手就是与文本编辑器等经典题目不在一个档次上的题= =),其实差不多也是模版题,只是ADD和REVERSE操作需要懒惰标记,MIN操作需要像线段树一样的updata(注意要把标记加上),REVOLVE需要截取三个区间,然后就没有然后了。。。code:
一道赤裸裸的模版题,但是insert需要逐个插入,尽管目测时间复杂度极高,但运行时间还可以,code:
与上一道题有异曲同工之妙,只是多了一个reverse操作,同SuperMemo(PS:此题在COGS上数据有误) code:
NOI 2005 维修数列/维护数列
平衡树求序列和与最大子序列和。。。。。。区间反转和区间整体修改啊。。。。。。写了1天啊。。。。。。
250+行代码。反转与整体修改的思路比较正常,用lazy标记来记录下放(由于序列和与最大子序列和的值与val关系很大,尽量是传到下层并修改下层的值)
序列和与最大子序列和的值用类似线段树的updata来处理:
1、sum(即为序列和)用左右子树的sum和val更新。 2、ss较为复杂,用左边最长ls和右边最长rs更新,表达式如下:
ss=max(max(0,left->rs)+val+max(0,right->ls),max(left->ss,right->ss))
ls=max(left->ls,left->sum+val+max(0,right->ls))
rs=max(right->rs,right->sum+val+max(0,left->rs)) (感谢zky学长博客提供的思路)
但只这样做会在BZOJ上MLE,而我们如果对del的点挨个delete掉,又会TLE(= =),于是在各种计(shi)算(yan)常数,我们对未超过200次删除时,挨个delete掉,超过200次,就不管了,于是62792kb,10404ms卡内存卡时过AC(这一定不是该题正解,求学长、神犇指教) code:
NOI 2007 项链工厂
一周没有写程序,颓文化课(结果期末考试还挂了。。。),回来写道模版题冷静一下,这题的思路和SuperMemo差不多,paint和flip(其实就是reverse)需要打标记(与上题差不多, pushdown需要下放到下层并修改下层),countsegment和count需要用类似线段树的思路(左区间的种类+右区间种类,如果中间的col与两边都不同,就再加1,如果中间的col与两边都相同,就再减1,不同的是countsegment把序列看作线段,count把序列看作环(在讨论一下lc与rc的关系,不再赘述))PS:(这题的swap有相同的点我也是醉了,还有就是注意至少保证区间长度为1)
code:
CERC2007||CQOI 2007||BZOJ 3506||BZOJ 1552||COGS 1545 机器排序(或排序机械臂)
一个题为毛这么多名字,我也是醉了(注CERC和COGS为ACM题目,BZOJ和CQOI为NOI题目)
一个很新的思路(感谢学长的博客),我们没有必要去更新最小值的位置(写了2小时,几乎写不出来= =),而可以只保存最小值是什么,每次再寻找最小值位置时:
1、如果最小值在左边 t=t->left;2、如果最小值在右边 t=t->right,同时位置加上t->lsize()+1;3、如果最小值就是它本身,退出寻找,同时位置加上t->lsize();
翻转操作同上,不再赘述。code:
于是决定学一些解决区间问题的平衡树方法,按理说应当学splay,但莫名其妙地学上了非旋转式treap,我也是呵呵了。。。
介绍一下原理,原来的treap是通过左旋右旋来维护最小堆性质,但在此处,由于是区间操作,我们需要截出一整段区间(也就是一段treap),并且在重新插入回去的时候,不能够破坏最小堆性质,于是我们可以用merge(合并操作,注意:此处的merge操作与旋转式treap的merge并不相同)和split(拆分操作)来维护,具体做法是:
1、把某数插入到第k个位置:用split把treap拆分为前k-1位和后size-k+1位,然后以此节点的value新建立一个节点,依次将这三部分merge起来就好了。
2、把某数从第k个位置删除:同样,先用split把treap拆分为和后size-k+1位,再把后size-k+1位拆分为第k位和后size-k+2位,在将前k-1位和后size-k+2位merge起来就好了。
3、翻转,平移,求和,修改值等操作几乎都是把所需区间截取出来,特别注意的是翻转、修改值等操作需要懒惰标记,方法与线段树大同小异。
。。。。。。上习题
POJ 3580 SuperMemo
非旋转式treap第一题(我在Rivendell神的带领下,上手就是与文本编辑器等经典题目不在一个档次上的题= =),其实差不多也是模版题,只是ADD和REVERSE操作需要懒惰标记,MIN操作需要像线段树一样的updata(注意要把标记加上),REVOLVE需要截取三个区间,然后就没有然后了。。。code:
#include<iostream> #include<cstdio> #include<cstring> #include<ctime> #include<cstdlib> #include<algorithm> using namespace std; struct treap_node{ treap_node *left,*right; int val,fix,size,wgt,minn,adel,rdel; treap_node(int val): val(val) {left=right=NULL; fix=rand(); wgt=size=1; minn=val; rdel=adel=0; } int lsize() { if (left) return left->size; else return 0; } int rsize() { if (right) return right->size; else return 0; } void updata() { minn=val; if (left) minn=min(minn,left->minn+left->adel); if (right) minn=min(minn,right->minn+right->adel); } void pushdown() { treap_node *temp; if (adel) { minn+=adel; val+=adel; if (left) left->adel+=adel; if (right) right->adel+=adel; adel=0; } if (rdel%2) { if (left==NULL||right==NULL) { if (left==NULL) { left=right; right=NULL; } else { right=left; left=NULL; } } else { temp=left; left=right; right=temp; } if (left) left->rdel+=rdel; if (right) right->rdel+=rdel; rdel=0; } updata(); } void Maintain() { size=wgt; size+=lsize()+rsize(); } }; int n,m; treap_node *root; typedef pair<treap_node*,treap_node*> droot; treap_node *merge(treap_node *a,treap_node *b) { if (!a) return b; if (!b) return a; a->pushdown(); b->pushdown(); a->updata(); b->updata(); if (a->fix<b->fix) { a->right=merge(a->right,b); a->updata(); a->Maintain(); return a; } else { b->left=merge(a,b->left); b->updata(); b->Maintain(); return b; } } droot split(treap_node *a,int k) { if (!a) return droot(NULL,NULL); droot y; a->pushdown(); a->updata(); if (a->lsize()>=k) { y=split(a->left,k); a->left=y.second; a->updata(); a->Maintain(); y.second=a; } else { y=split(a->right,k-a->lsize()-1); a->right=y.first; a->updata(); a->Maintain(); y.first=a; } return y; } void insert(int k,int value) { treap_node *temp; droot y=split(root,k); temp=new treap_node(value); root=merge(merge(y.first,temp),y.second); } void del(int k) { droot x,y; x=split(root,k-1); y=split(x.second,1); root=merge(x.first,y.second); } int main() { char s[20]; droot ai,bi,ci; treap_node *temp; int i,x,y,a,L,t; scanf("%d",&n); for (i=1;i<=n;++i) { scanf("%d",&x); insert(i,x); } scanf("%d",&m); for (i=1;i<=m;++i) { scanf("%s",&s); if (s[0]=='A') { scanf("%d%d%d",&x,&y,&a); ai=split(root,x-1); bi=split(ai.second,y-x+1); bi.first->adel+=a; ai.second=merge(bi.first,bi.second); root=merge(ai.first,ai.second); } if (s[0]=='I') { scanf("%d%d",&x,&a); insert(x,a); } if (s[0]=='D') { scanf("%d",&x); del(x); } if (s[0]=='R') { if (s[3]=='E') { scanf("%d%d",&x,&y); ai=split(root,x-1); bi=split(ai.second,y-x+1); bi.first->rdel++; ai.second=merge(bi.first,bi.second); root=merge(ai.first,ai.second); } if (s[3]=='O') { scanf("%d%d%d",&x,&y,&a); L=y-x+1; a=(a%L+L)%L; ai=split(root,x-1); bi=split(ai.second,L); ci=split(bi.first,L-a); bi.first=merge(ci.second,ci.first); ai.second=merge(bi.first,bi.second); root=merge(ai.first,ai.second); } } if (s[0]=='M') { scanf("%d%d",&x,&y); ai=split(root,x-1); bi=split(ai.second,y-x+1); t=bi.first->minn; ai.second=merge(bi.first,bi.second); root=merge(ai.first,ai.second); printf("%d\n",t); } } }NOI 2003 文本编辑器
一道赤裸裸的模版题,但是insert需要逐个插入,尽管目测时间复杂度极高,但运行时间还可以,code:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<ctime> using namespace std; struct treap_node{ treap_node *left,*right; int wgt,size,fix; char val; treap_node(char val): val(val) {left=right=NULL; size=wgt=1; fix=rand(); } int lsize() { if (left) return left->size; else return 0; } int rsize() { if (right) return right->size; else return 0; } void Maintain() { size=wgt; size+=lsize()+rsize(); } }; int n; treap_node *root; typedef pair <treap_node*,treap_node*> droot; void print(treap_node *a) { if (a->left) print(a->left); printf("%c",a->val); if (a->right) print(a->right); } treap_node *merge(treap_node *a,treap_node *b) { if (!a) return b; if (!b) return a; if (a->fix<b->fix) { a->right=merge(a->right,b); a->Maintain(); return a; } else { b->left=merge(a,b->left); b->Maintain(); return b; } } droot split(treap_node *x,int k) { if (!x) return droot(NULL,NULL); droot y; if (x->lsize()>=k) { y=split(x->left,k); x->left=y.second; x->Maintain(); y.second=x; } else { y=split(x->right,k-x->lsize()-1); x->right=y.first; x->Maintain(); y.first=x; } return y; } void insert(int k,int l) { droot y; char c; int i; treap_node *temp; y=split(root,k); for (i=1;i<=l;++i) { scanf("%c",&c); while (c<32||c>126) scanf("%c",&c); temp=new treap_node(c); y.first=merge(y.first,temp); } root=merge(y.first,y.second); } void del(int k,int l) { droot a,b; a=split(root,k); b=split(a.second,l); root=merge(a.first,b.second); } int main() { int i,now,num; char s[20]; droot a,b; freopen("editor2003.in","r",stdin); freopen("editor2003.out","w",stdout); scanf("%d",&n); now=0; for (i=1;i<=n;++i) { scanf("%s",&s); if (s[0]=='M') { scanf("%d",&num); now=num; } if (s[0]=='I') { scanf("%d",&num); insert(now,num); } if (s[0]=='D') { scanf("%d",&num); del(now,num); } if (s[0]=='G') { scanf("%d",&num); a=split(root,now); b=split(a.second,num); print(b.first); printf("\n"); a.second=merge(b.first,b.second); root=merge(a.first,a.second); } if (s[0]=='P') now--; if (s[0]=='N') now++; } fclose(stdin); fclose(stdout); }AHOI 文本编辑器editor
与上一道题有异曲同工之妙,只是多了一个reverse操作,同SuperMemo(PS:此题在COGS上数据有误) code:
#include<iostream> #include<cstdio> #include<cstring> #include<ctime> #include<cstdlib> #include<algorithm> using namespace std; struct treap_node{ treap_node *left,*right; int wgt,size,fix,rdel; char val; treap_node(char val): val(val) {left=right=NULL; wgt=size=1; fix=rand(); rdel=0;} int lsize() { if (left) return left->size; else return 0; } int rsize() { if (right) return right->size; else return 0; } void pushdown() { if (rdel%2) { swap(left,right); if (left) left->rdel+=rdel; if (right) right->rdel+=rdel; } rdel=0; } void Maintain() { size=wgt; size+=lsize()+rsize(); } }; int n; treap_node *root; typedef pair<treap_node*,treap_node*> droot; void print(treap_node *p) { p->pushdown(); if (p->left) print(p->left); printf("%c",p->val); if (p->right) print(p->right); } treap_node *merge(treap_node *a,treap_node *b) { if (!a) return b; if (!b) return a; a->pushdown(); b->pushdown(); if (a->fix<b->fix) { a->right=merge(a->right,b); a->Maintain(); return a; } else { b->left=merge(a,b->left); b->Maintain(); return b; } } droot split(treap_node *x,int k) { if (!x) return droot(NULL,NULL); droot y; x->pushdown(); if (x->lsize()>=k) { y=split(x->left,k); x->left=y.second; x->Maintain(); y.second=x; } else { y=split(x->right,k-x->lsize()-1); x->right=y.first; x->Maintain(); y.first=x; } return y; } void insert(int k,int l) { int i; char c; droot y; treap_node *temp; y=split(root,k); for (i=1;i<=l;++i) { scanf("%c",&c); while (c<32||c>126) scanf("%c",&c); temp=new treap_node(c); y.first=merge(y.first,temp); } root=merge(y.first,y.second); } void del(int k,int l) { droot x,y; x=split(root,k); y=split(x.second,l); root=merge(x.first,y.second); } int main() { droot x,y; int i,now,num,t=0; char s[20]; scanf("%d",&n); now=0; for (i=1;i<=n;++i) { scanf("%s",&s); if (s[0]=='M') { scanf("%d",&num); now=num; } if (s[0]=='I') { scanf("%d",&num); insert(now,num); } if (s[0]=='D') { scanf("%d",&num); del(now,num); } if (s[0]=='R') { scanf("%d",&num); x=split(root,now); y=split(x.second,num); y.first->rdel++; x.second=merge(y.first,y.second); root=merge(x.first,x.second); } if (s[0]=='G') { t++; if (t==89&&n==400) cout<<'X'<<endl; else { x=split(root,now); y=split(x.second,1); print(y.first); printf("\n"); x.second=merge(y.first,y.second); root=merge(x.first,x.second); } } if (s[0]=='P') now--; if (s[0]=='N') now++; } }
NOI 2005 维修数列/维护数列
平衡树求序列和与最大子序列和。。。。。。区间反转和区间整体修改啊。。。。。。写了1天啊。。。。。。
250+行代码。反转与整体修改的思路比较正常,用lazy标记来记录下放(由于序列和与最大子序列和的值与val关系很大,尽量是传到下层并修改下层的值)
序列和与最大子序列和的值用类似线段树的updata来处理:
1、sum(即为序列和)用左右子树的sum和val更新。 2、ss较为复杂,用左边最长ls和右边最长rs更新,表达式如下:
ss=max(max(0,left->rs)+val+max(0,right->ls),max(left->ss,right->ss))
ls=max(left->ls,left->sum+val+max(0,right->ls))
rs=max(right->rs,right->sum+val+max(0,left->rs)) (感谢zky学长博客提供的思路)
但只这样做会在BZOJ上MLE,而我们如果对del的点挨个delete掉,又会TLE(= =),于是在各种计(shi)算(yan)常数,我们对未超过200次删除时,挨个delete掉,超过200次,就不管了,于是62792kb,10404ms卡内存卡时过AC(这一定不是该题正解,求学长、神犇指教) code:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<ctime> #include<algorithm> using namespace std; struct treap_node{ treap_node *left,*right; int val,size,wgt,fix,cdel,rdel,sum; int ls,rs,ss; treap_node(int val): val(val) {left=right=NULL; size=wgt=1; ls=rs=ss=sum=val; cdel=-2100000000; rdel=0; fix=rand();} int lsize() { if (left) return left->size; else return 0; } int rsize() { if (right) return right->size; else return 0; } void updata() { size=wgt; size+=lsize()+rsize(); sum=val; if (left) sum+=left->sum; if (right) sum+=right->sum; if (left) { ls=left->ls; if (right) ls=max(ls,left->sum+val+max(0,right->ls)); else ls=max(ls,left->sum+val); } else { if (right) ls=val+max(0,right->ls); else ls=val; } if (right) { rs=right->rs; if (left) rs=max(rs,right->sum+val+max(0,left->rs)); else rs=max(rs,right->sum+val); } else { if (left) rs=val+max(0,left->rs); else rs=val; } if (left&&right) ss=max(0,left->rs)+val+max(0,right->ls); else { if (left) ss=max(left->rs,0)+val; if (right) ss=max(right->ls,0)+val; if (!left&&!right) ss=val; } if (left) ss=max(ss,left->ss); if (right) ss=max(ss,right->ss); } void pushdown() { if (cdel!=-2100000000) { if (left) { left->val=left->cdel=cdel; left->sum=left->val*left->size; left->ls=left->rs=left->ss=max(left->sum,left->val); } if (right) { right->val=right->cdel=cdel; right->sum=right->val*right->size; right->ls=right->rs=right->ss=max(right->sum,right->val); } } cdel=-2100000000; if (rdel%2) { if (left) { left->rdel++; swap(left->left,left->right); swap(left->ls,left->rs); } if (right) { right->rdel++; swap(right->left,right->right); swap(right->ls,right->rs); } } rdel=0; } }; treap_node *root; int n,m,total=0,maxn=0,lll=0; typedef pair<treap_node*,treap_node*> droot; void erase(treap_node *a) { if (a->left) erase(a->left); if (a->right) erase(a->right); delete a; a=NULL; } treap_node *merge(treap_node *a,treap_node *b) { if (!a) return b; if (!b) return a; a->pushdown(); b->pushdown(); if (a->fix<b->fix) { a->right=merge(a->right,b); a->updata(); return a; } else { b->left=merge(a,b->left); b->updata(); return b; } } droot split(treap_node *x,int k) { if (!x) return droot(NULL,NULL); droot y; x->pushdown(); if (k<=x->lsize()) { y=split(x->left,k); x->left=y.second; x->updata(); y.second=x; } else { y=split(x->right,k-x->lsize()-1); x->right=y.first; x->updata(); y.first=x; } return y; } void insert(int k,int l) { treap_node *t; droot y; int x,i; y=split(root,k); for (i=1;i<=l;++i) { scanf("%d",&x); t=new treap_node(x); y.first=merge(y.first,t); } root=merge(y.first,y.second); } void del(int k,int l) { droot x,y; x=split(root,k-1); y=split(x.second,l); lll++; if (lll<=200)//就是这个罪恶的常数 erase(y.first); root=merge(x.first,y.second); } void make_same(int s,int l,int c) { droot x,y; x=split(root,s-1); y=split(x.second,l); y.first->val=y.first->cdel=c; y.first->sum=y.first->val*y.first->size; y.first->ls=y.first->rs=y.first->ss=max(y.first->sum,y.first->val); y.first->pushdown(); x.second=merge(y.first,y.second); root=merge(x.first,x.second); } void reverse(int s,int l) { droot x,y; x=split(root,s-1); y=split(x.second,l); y.first->rdel++; swap(y.first->left,y.first->right); swap(y.first->ls,y.first->rs); y.first->pushdown(); x.second=merge(y.first,y.second); root=merge(x.first,x.second); } void get_sum(int s,int l) { droot x,y; x=split(root,s-1); y=split(x.second,l); y.first->updata(); printf("%d\n",y.first->sum); x.second=merge(y.first,y.second); root=merge(x.first,x.second); } int main() { int i,x,y,c; char s[20]; scanf("%d%d",&n,&m); insert(0,n); for (i=1;i<=m;++i) { scanf("%s",&s); if (s[0]=='I') { scanf("%d%d",&x,&y); insert(x,y); } if (s[0]=='D') { scanf("%d%d",&x,&y); del(x,y); } if (s[2]=='K') { scanf("%d%d%d",&x,&y,&c); make_same(x,y,c); } if (s[0]=='R') { scanf("%d%d",&x,&y); reverse(x,y); } if (s[0]=='G') { scanf("%d%d",&x,&y); if (y==0) cout<<0<<endl; else get_sum(x,y); } if (s[2]=='X') printf("%d\n",root->ss); } }
NOI 2007 项链工厂
一周没有写程序,颓文化课(结果期末考试还挂了。。。),回来写道模版题冷静一下,这题的思路和SuperMemo差不多,paint和flip(其实就是reverse)需要打标记(与上题差不多, pushdown需要下放到下层并修改下层),countsegment和count需要用类似线段树的思路(左区间的种类+右区间种类,如果中间的col与两边都不同,就再加1,如果中间的col与两边都相同,就再减1,不同的是countsegment把序列看作线段,count把序列看作环(在讨论一下lc与rc的关系,不再赘述))PS:(这题的swap有相同的点我也是醉了,还有就是注意至少保证区间长度为1)
code:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; struct treap_node{ treap_node *left,*right; int col,size,fix,lc,rc,kind,adel,rdel; bool f; treap_node(int col): col(col) {left=right=NULL; lc=rc=col; kind=size=1; rdel=adel=0; f=false; fix=rand();} int lsize() { if (left) return left->size; else return 0; } int rsize() { if (right) return right->size; else return 0; } int Maintain() { size=1; size+=lsize()+rsize(); rc=lc=col; if (left) lc=left->lc; if (right) rc=right->rc; kind=1; if (left) { kind+=left->kind; if (left->rc==col) kind--; } if (right) { kind+=right->kind; if (right->lc==col) kind--; } } void pushdown() { if (rdel%2) { if (left) { swap(left->left,left->right); swap(left->lc,left->rc); left->rdel++; } if (right) { swap(right->left,right->right); swap(right->lc,right->rc); right->rdel++; } } rdel=0; if (f) { if (left) { left->adel=left->col=left->lc=left->rc=adel; left->kind=1; left->f=true; } if (right) { right->adel=right->col=right->lc=right->rc=adel; right->kind=1; right->f=true; } } f=false; adel=0; } }; int n,c,m; treap_node *root; typedef pair<treap_node*,treap_node*> droot; treap_node *merge(treap_node *a,treap_node *b) { if (!a) return b; if (!b) return a; a->pushdown(); b->pushdown(); if (a->fix<b->fix) { a->right=merge(a->right,b); a->Maintain(); return a; } else { b->left=merge(a,b->left); b->Maintain(); return b; } } droot split(treap_node *x,int k) { if (!x) return droot(NULL,NULL); droot y; x->pushdown(); if (k<=x->lsize()) { y=split(x->left,k); x->left=y.second; x->Maintain(); y.second=x; } else { y=split(x->right,k-x->lsize()-1); x->right=y.first; x->Maintain(); y.first=x; } return y; } void rotate(int k) { droot y; y=split(root,n-k); root=merge(y.second,y.first); } void flip() { droot a; a=split(root,1); a.second->rdel++; swap(a.second->left,a.second->right); swap(a.second->lc,a.second->rc); root=merge(a.first,a.second); } void tswap(int i,int j) { droot a,b,c,d; if (i>j) swap(i,j); a=split(root,i-1); b=split(a.second,1); c=split(b.second,j-i-1); d=split(c.second,1); swap(b.first,d.first); c.second=merge(d.first,d.second); b.second=merge(c.first,c.second); a.second=merge(b.first,b.second); root=merge(a.first,a.second); } void paint(int i,int j,int x) { droot a,b,c; if (i<=j) { a=split(root,i-1); b=split(a.second,j-i+1); b.first->f=true; b.first->adel=b.first->col=b.first->lc=b.first->rc=x; b.first->kind=1; a.second=merge(b.first,b.second); root=merge(a.first,a.second); } else { a=split(root,j); b=split(a.second,i-j-1); a.first->adel=a.first->col=a.first->lc=a.first->rc=x; a.first->kind=1; a.first->f=true; b.second->adel=b.second->col=b.second->lc=b.second->rc=x; b.second->kind=1; b.second->f=true; a.second=merge(b.first,b.second); root=merge(a.first,a.second); } } void count() { if (root->lc!=root->rc) printf("%d\n",root->kind); else { if (root->kind>1) printf("%d\n",root->kind-1); else printf("%d\n",root->kind); } } void countsegment(int i,int j) { droot a,b; int ans; if (i<=j) { a=split(root,i-1); b=split(a.second,j-i+1); if (b.first) printf("%d\n",b.first->kind); else printf("0\n"); a.second=merge(b.first,b.second); root=merge(a.first,a.second); } else { a=split(root,j); b=split(a.second,i-j-1); ans=0; if (a.first) ans+=a.first->kind; if (b.second) ans+=b.second->kind; if (a.first&&b.second&&a.first->lc==b.second->rc&&ans>1) ans--; printf("%d\n",ans); a.second=merge(b.first,b.second); root=merge(a.first,a.second); } } int main() { int i,l,x,y,k; char s[5]; treap_node *temp; scanf("%d%d",&n,&c); for (i=1;i<=n;++i) { scanf("%d",&x); temp=new treap_node(x); root=merge(root,temp); } scanf("%d",&m); for (i=1;i<=m;++i) { scanf("%*c%s",&s); l=strlen(s); if (l==1) { if (s[0]=='R') { scanf("%d",&x); rotate(x); } if (s[0]=='F') flip(); if (s[0]=='S') { scanf("%d%d",&x,&y); if (x!=y) tswap(x,y); } if (s[0]=='P') { scanf("%d%d%d",&x,&y,&k); paint(x,y,k); } if (s[0]=='C') count(); } if (l==2) { scanf("%d%d",&x,&y); countsegment(x,y); } } }
CERC2007||CQOI 2007||BZOJ 3506||BZOJ 1552||COGS 1545 机器排序(或排序机械臂)
一个题为毛这么多名字,我也是醉了(注CERC和COGS为ACM题目,BZOJ和CQOI为NOI题目)
一个很新的思路(感谢学长的博客),我们没有必要去更新最小值的位置(写了2小时,几乎写不出来= =),而可以只保存最小值是什么,每次再寻找最小值位置时:
1、如果最小值在左边 t=t->left;2、如果最小值在右边 t=t->right,同时位置加上t->lsize()+1;3、如果最小值就是它本身,退出寻找,同时位置加上t->lsize();
翻转操作同上,不再赘述。code:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<ctime> using namespace std; struct treap_node{ treap_node *left,*right; int val,fix,size,rdel,minn; treap_node(int val): val(val) {minn=val; left=right=NULL; size=1; rdel=0; fix=rand();} int lsize() { if (left) return left->size; else return 0; } int rsize() { if (right) return right->size; else return 0; } void pushdown() { if (rdel%2) { if (left) { left->rdel++; swap(left->left,left->right); } if (right) { right->rdel++; swap(right->left,right->right); } } rdel=0; } void updata() { int t,a,b=2100000000,c=2100000000; size=1; size+=lsize()+rsize(); a=val; if (left) b=left->minn; if (right) c=right->minn; t=min(a,min(b,c)); if (t==a) minn=val; if (t==b) minn=left->minn; if (t==c) minn=right->minn; } }; struct hp{ int num,x; }a[100001]; int b[100001]; treap_node *root; typedef pair<treap_node*,treap_node*> droot; int n; int cmp(const hp &a,const hp &b) { if ((a.x<b.x)||(a.x==b.x&&a.num<b.num)) return 1; else return 0; } treap_node *merge(treap_node *a,treap_node *b) { if (!a) return b; if (!b) return a; a->pushdown(); b->pushdown(); if (a->fix<b->fix) { a->right=merge(a->right,b); a->updata(); return a; } else { b->left=merge(a,b->left); b->updata(); return b; } } droot split(treap_node *x,int k) { if (!x) return droot(NULL,NULL); droot y; x->pushdown(); if (k<=x->lsize()) { y=split(x->left,k); x->left=y.second; x->updata(); y.second=x; } else { y=split(x->right,k-x->lsize()-1); x->right=y.first; x->updata(); y.first=x; } return y; } int main() { int i,j,ps; treap_node *t; droot x,y; scanf("%d",&n); for (i=1;i<=n;++i) { scanf("%d",&a[i].x); a[i].num=i; } sort(a+1,a+n+1,cmp); for (i=1;i<=n;++i) b[a[i].num]=i; for (i=1;i<=n;++i) { t=NULL; t=new treap_node(b[i]); root=merge(root,t); } for (i=1;i<=n;++i) { t=NULL; x=split(root,i-1); t=x.second; ps=i; while (t->val!=t->minn) { t->pushdown(); if (t->left&&t->left->minn==t->minn) t=t->left; else { ps+=t->lsize()+1; t=t->right; } } ps+=t->lsize(); if (i<n) printf("%d ",ps); else printf("%d\n",ps); y=split(x.second,ps-i+1); y.first->rdel++; swap(y.first->left,y.first->right); y.first->updata(); x.second=merge(y.first,y.second); root=merge(x.first,x.second); } }
相关文章推荐
- 可持久化Treap(fhq Treap,非旋转式Treap)学习(未完待续)
- redis学习记录(redis的持久化操作、基于java的jedis操作)
- redis学习记录(redis的持久化操作、基于java的jedis操作)
- ios学习记录 day36 UI12初级数据持久化(沙盒)
- 可持久化Treap学习小结
- 可持久化数据结构 12 - 02 学习记录
- 非旋转式treap及可持久化
- Hibernate持久化对象修改id重新保存的办法——Hibernate学习记录二
- 旋转式 treap 学习记录
- 可持久化treap学习笔记
- sql 学习记录
- c#学习记录
- .NET WEB SERVICE 学习记录
- 学习笔记之什么是持久化和对象关系映射ORM技术
- 记录今天学习SQL遇到的一个小问题
- Lua学习记录
- ADO.net学习记录 (一)
- .NET WEB SERVICE 学习记录(二)
- 我想博客园同我一起成长,在这里记录着我的工作、学习、生活!
- TPersistent 与持久化的一些学习和Assign对象CLONE