CODEVS 3243 区间翻转 (SBT)

来源:互联网 发布:深圳知创科技有限公司 编辑:程序博客网 时间:2024/06/05 05:10

SBT实现区间翻转:

框架还是SBT的框架,加个翻转标记,旋转时记得维护标记,加个函数,把某棵树的根设置为树中第k大的数。

然后翻转区间L,R 就是把根转成R+1,再把左子树转成L-1,然后根的左子树的右子树就是所要翻转的区间,给它加个翻转标记就解决了。

为了能够翻转从1开始的区间,和到n的区间,在树的最前和最后各加了一个无用的元素。

每次翻转之后平衡一次的话,效率会降低,所以就省去了平衡函数。

在CODEVS上测得总耗时  755ms 。

/*作者:Zearot题目:p3243 区间翻转*/#include<cstdio>#include<iostream>#include<cstring>#define maxn 150007using namespace std; int L[maxn],R[maxn],S[maxn],K[maxn],IP;//Left,Right,Size,Key,指针 bool Turn[maxn];//翻转标记,被标记的点未翻转 int ANS[maxn],ANSIP;void PushDown(int rt){if(Turn[rt]){Turn[L[rt]]^=1;Turn[R[rt]]^=1;swap(L[rt],R[rt]);Turn[rt]=0;}}void zig(int &rt){PushDown(rt);PushDown(R[rt]);int t=R[rt];R[rt]=L[t];L[t]=rt;S[t]=S[rt];S[rt]=1+S[L[rt]]+S[R[rt]];rt=t; }void zag(int &rt){PushDown(rt);PushDown(L[rt]);int t=L[rt];L[rt]=R[t];R[t]=rt;S[t]=S[rt];S[rt]=1+S[L[rt]]+S[R[rt]];rt=t;}int n,m;void Build(int &rt,int A,int B){//K下标为0到n+1的数据建树 int M=(A+B)>>1;rt=++IP;L[rt]=R[rt]=0;S[rt]=B-A+1;K[rt]=ANS[M];if(A < M) Build(L[rt],A,M-1);if(B > M) Build(R[rt],M+1,B);}void Show(int &rt){PushDown(rt);if(L[rt]) Show(L[rt]);ANS[ANSIP++]=K[rt];if(R[rt]) Show(R[rt]);}void SetRootTo(int &rt,int k){//改成非递归的话,效率可以提高 PushDown(rt);if(S[L[rt]]+1==k) return;if(S[L[rt]]>=k){SetRootTo(L[rt],k);zag(rt);return;}else {SetRootTo(R[rt],k-S[L[rt]]-1);zig(rt);return;}}void Reverse(int &rt,int Left,int Right){SetRootTo(rt,Right+2);SetRootTo(L[rt],Left);Turn[R[L[rt]]]^=1;}int main(void){scanf("%d",&n);for(int i=1;i<=n;++i) scanf("%d",&ANS[i]);int rt=0;IP=0;Build(rt,0,n+1);scanf("%d",&m);for(int i=0;i<m;++i){ int Left,Right;scanf("%d%d",&Left,&Right); //翻转操作  Reverse(rt,Left,Right); } ANSIP=0; Show(rt); for(int i=1;i<=n;++i){ printf("%d",ANS[i]); if(i==n) printf("\n"); else printf(" "); }    return 0;}



0 0
原创粉丝点击