BZOJ3223文艺平衡树——非旋转treap
此為平衡樹(shù)系列第二道:文藝平衡樹(shù)您需要寫(xiě)一種數(shù)據(jù)結(jié)構(gòu),來(lái)維護(hù)一個(gè)有序數(shù)列,其中需要提供以下操作:
翻轉(zhuǎn)一個(gè)區(qū)間,例如原有序序列是5 4 3 2 1,翻轉(zhuǎn)區(qū)間是[2,4]的話,結(jié)果是5 2 3 4 1
輸入
第一行為n,m n表示初始序列有n個(gè)數(shù),這個(gè)序列依次是(1,2……n-1,n) m表示翻轉(zhuǎn)操作次數(shù)
接下來(lái)m行每行兩個(gè)數(shù)[l,r] 數(shù)據(jù)保證 1<=l<=r<=n
輸出
輸出一行n個(gè)數(shù)字,表示原始序列經(jīng)過(guò)m次變換后的結(jié)果
樣例輸入
5 3 1 3 1 3 1 4樣例輸出
4 3 2 1 5提示
n,m<=100000
非旋轉(zhuǎn)treap相比于旋轉(zhuǎn)treap支持區(qū)間操作,所以對(duì)于這道題只需要每次把樹(shù)拆成[1~l-1]、[l~r]、[r+1~tot]三段,然后把[l~r]打上標(biāo)記進(jìn)行翻轉(zhuǎn),再把三段區(qū)間合并就行了。對(duì)于打標(biāo)記的點(diǎn)只有在查到這個(gè)點(diǎn)時(shí)才翻轉(zhuǎn),如果一個(gè)點(diǎn)被打了兩次標(biāo)記就相當(dāng)于不翻轉(zhuǎn)。
最后附上代碼.
指針版
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define ll long long using namespace std; char *p1,*p2,buf[100000]; #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int rd() {int x=0,f=1; char c=nc(); while(!isdigit(c)) {if(c=='-') f=-1; c=nc();} while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;} ll rd2() {ll x=0,f=1; char c=nc(); while(!isdigit(c)) {if(c=='-') f=-1; c=nc();} while(isdigit(c)) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x*f;} int n,m; int L,R; struct treap {int size;int rnd;int val;int rev;treap *ls,*rs;treap(){}treap(int k,treap *son){size=1;rnd=rand();val=k;ls=rs=son;rev=0;}void pushup(){size=ls->size+rs->size+1;}void pushdown(){if(rev){rev^=1;ls->rev^=1;rs->rev^=1;swap(ls,rs);}} }tr[100010],nil; typedef treap* node; node root,cnt,null; void init() {nil=treap(0,NULL);null=&nil;null->ls=null->rs=null;null->size=0;root=null;cnt=tr; } node build(int x) {*cnt=treap(x,null);return cnt++; } node merge(node x,node y) {if(x==null){return y; }if(y==null){return x;}x->pushdown();y->pushdown();if(x->rnd<y->rnd){x->rs=merge(x->rs,y);x->pushup();return x;}else{y->ls=merge(x,y->ls);y->pushup();return y;} } void split(node rt,node &x,node &y,int k) {if(rt==null){x=y=null;return ;}rt->pushdown();if(rt->ls->size>=k){y=rt;split(rt->ls,x,y->ls,k);rt->pushup();}else{x=rt;split(rt->rs,x->rs,y,k-rt->ls->size-1);rt->pushup();} } void print(node rt) {rt->pushdown();if(rt->ls!=null){print(rt->ls);}printf("%d",rt->val);if(--n!=0){printf(" ");}if(rt->rs!=null){print(rt->rs);} } node build_tree(int l,int r) {if(l==r){return build(l);}int mid=(l+r)>>1;return merge(build_tree(l,mid),build_tree(mid+1,r)); } int main() {init();n=rd();m=rd();root=build_tree(1,n);while(m--){L=rd();R=rd();node x,y,z;split(root,y,z,R);split(y,x,y,L-1);y->rev^=1;root=merge(merge(x,y),z);}print(root); }非指針版
#include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> using namespace std; int n,m; int r[100010]; int v[100010]; int s[100010][3]; int size[100010]; bool d[100010]; int root; int tot; int L,R; int x,y,z; int flag; void pushup(int x) {size[x]=size[s[x][0]]+size[s[x][1]]+1; } int build(int x) {v[++tot]=x;r[tot]=rand();size[tot]=1;return tot; } void pushdown(int x) {swap(s[x][0],s[x][1]);if(s[x][0]){d[s[x][0]]^=1;}if(s[x][1]){d[s[x][1]]^=1;}d[x]=0; } int merge(int x,int y) {if(!x||!y){return x+y;}if(r[x]<r[y]){if(d[x]){pushdown(x);}s[x][1]=merge(s[x][1],y);pushup(x);return x;}else{if(d[y]){pushdown(y);}s[y][0]=merge(x,s[y][0]);pushup(y);return y;} } void split(int i,int k,int &x,int &y) {if(!i){x=y=0;return ;}if(d[i]){pushdown(i);}if(size[s[i][0]]<k){x=i;split(s[i][1],k-size[s[i][0]]-1,s[i][1],y);}else{y=i;split(s[i][0],k,x,s[i][0]);}pushup(i); } void print(int x) {if(!x){return ;}if(d[x]){pushdown(x);}print(s[x][0]);if(flag==0){printf("%d",v[x]);flag=1;}else{printf(" %d",v[x]);}print(s[x][1]); } int main() {srand(12378);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){root=merge(root,build(i));}for(int i=1;i<=m;i++){scanf("%d%d",&L,&R);split(root,L-1,x,y);split(y,R-L+1,y,z);d[y]^=1;root=merge(merge(x,y),z);}print(root);return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/Khada-Jhin/p/9090646.html
總結(jié)
以上是生活随笔為你收集整理的BZOJ3223文艺平衡树——非旋转treap的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。