传送门
非旋treap维护区间反转简单题。
很板的一道题。
fhq_treap真心好些,安利一波。
只需要写
m
e
r
g
e
,
s
p
l
i
t
merge,split
merge,split两个操作,并且及时的下穿标记与合并信息就行了。
代码:
#include<bits/stdc++.h>
#define N 300005
#define lc son[p][0]
#define rc son[p][1]
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
typedef pair<int,int> pii;
struct Treap{
int son[N][2],siz[N],tag[N],val[N],rt,tot,rd[N];
inline void pushup(int p){siz[p]=siz[lc]+siz[rc]+1;}
inline void pushdown(int p){
if(tag[p]){
swap(lc,rc);
if(lc)tag[lc]^=1;
if(rc)tag[rc]^=1;
tag[p]^=1;
}
}
inline int newnode(int v){return val[++tot]=v,siz[tot]=1,rd[tot]=rand(),tot;}
inline int merge(int a,int b){
if(!a||!b)return a+b;
if(rd[a]<rd[b])return pushdown(a),son[a][1]=merge(son[a][1],b),pushup(a),a;
return pushdown(b),son[b][0]=merge(a,son[b][0]),pushup(b),b;
}
inline pii split(int p,int k){
if(!p)return pii(0,0);
pii ans,tmp;
pushdown(p);
if(siz[lc]>=k){
tmp=split(lc,k),ans.first=tmp.first,ans.second=p,lc=tmp.second,pushup(p);
return ans;
}
tmp=split(rc,k-siz[lc]-1),ans.second=tmp.second,ans.first=p,rc=tmp.first,pushup(p);
return ans;
}
}T;
int n;
int main(){
T.rt=T.tot=0,srand(time(NULL));
n=read();
for(int i=1;i<=n;++i){
int v=read();
T.rt=T.merge(T.rt,T.newnode(v));
}
int tim=0;
while(1){
pii x=T.split(T.rt,1);
T.pushdown(T.rt),T.rt=T.merge(x.first,x.second);
if(T.val[x.first]==1)return printf("%d",tim),0;
++tim,x=T.split(T.rt,T.val[x.first]),T.tag[x.first]^=1,T.rt=T.merge(x.first,x.second);
}
return 0;
}