在做完郁闷的出纳员、宠物收养所等题之后,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:
#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);
}
}