题目链接:点我~~
题意:给定n个数,有两种操作区间切割和区间翻转,求m次操作后的序列。
思路:对于区间切割,先将[l,r]取出来,再合并到c到c+1之间。(区间切割,区间翻转)
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PI; typedef pair< PI, int> PII; const double eps=1e-5; const double pi=acos(-1.0); const int mod=1e9+7; const int INF=0x3f3f3f3f; #define Key_value ch[ch[root][1]][0] const int MAXN = 300100; const int MAXM = 20100; int pre[MAXN],ch[MAXN][2],size[MAXN],rev[MAXN],key[MAXN]; int root,tot1; int n; void NewNode(int &r,int father,int k) { r=++tot1; pre[r]=father; ch[r][0]=ch[r][1]=0; size[r]=1; rev[r]=0; key[r]=k; } //反转的更新 void Update_Rev(int r) { if(!r)return; swap(ch[r][0],ch[r][1]); rev[r]^=1; } void Push_Up(int r) { size[r]=size[ch[r][0]]+size[ch[r][1]]+1; } void Push_Down(int r) { if(rev[r]) { Update_Rev(ch[r][0]); Update_Rev(ch[r][1]); rev[r]=0; } } void Build(int &x,int l,int r,int father) { if(l>r)return; int mid=(l+r)/2; NewNode(x,father,mid); Build(ch[x][0],l,mid-1,x); Build(ch[x][1],mid+1,r,x); Push_Up(x); } void Init() { root=tot1=0; ch[root][0]=ch[root][1]=size[root]=rev[root]=key[root]=0; NewNode(root,0,-1); //不加边界点 居然T了。。why? NewNode(ch[root][1],root,-1); Build(Key_value,1,n,ch[root][1]); //Build(root,1,n,0); Push_Up(ch[root][1]); Push_Up(root); } //旋转,0为左旋,1为右旋 void Rotate(int x,int kind) { int y=pre[x]; Push_Down(y); Push_Down(x); ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y]; ch[x][kind]=y; pre[y]=x; Push_Up(y); } //Splay调整,将r结点调整到goal下面 void Splay(int r,int goal) { Push_Down(r); while(pre[r]!=goal) { if(pre[pre[r]]==goal) { //这题有反转操作,需要先push_down,在判断左右孩子 Push_Down(pre[r]); Push_Down(r); Rotate(r,ch[pre[r]][0]==r); } else { //这题有反转操作,需要先push_down,在判断左右孩子 Push_Down(pre[pre[r]]); Push_Down(pre[r]); Push_Down(r); int y=pre[r]; int kind=(ch[pre[y]][0]==y); //两个方向不同,则先左旋再右旋 if(ch[y][kind]==r) { Rotate(r,!kind); Rotate(r,kind); } //两个方向相同,相同方向连续两次 else { Rotate(y,kind); Rotate(r,kind); } } } Push_Up(r); if(goal==0)root=r; } int Get_kth(int r,int k) { Push_Down(r); int t=size[ch[r][0]] + 1; if(t==k)return r; if(t>k)return Get_kth(ch[r][0],k); else return Get_kth(ch[r][1],k-t); } void cut(int l,int r,int c) { Splay(Get_kth(root,l),0); Splay(Get_kth(root,r+2),root); int tmp=Key_value; Key_value=0; //将区间[l,r]分离 Push_Up(ch[root][1]); Push_Up(root); //更新节点信息 Splay(Get_kth(root,c+1),0); Splay(Get_kth(root,c+2),root); Key_value=tmp; pre[Key_value]=ch[root][1]; //合并 Push_Up(ch[root][1]); Push_Up(root); } void Reverse(int l,int r) { Splay(Get_kth(root,l),0); Splay(Get_kth(root,r+2),root); Update_Rev(Key_value); Push_Up(ch[root][1]); Push_Up(root); } int cnt; void InOrder(int r) { if(!r)return; Push_Down(r); InOrder(ch[r][0]); if(cnt>=1&&cnt<=n) { printf("%d",key[r]); if(cnt<n)printf(" "); else printf("\n"); } cnt++; InOrder(ch[r][1]); } void Treavel(int x) { if(x) { Treavel(ch[x][0]); printf("结点:%2d: 左儿子 %2d 右儿子 %2d 父结点 %2d size\ = %2d rev= %d\n",x,ch[x][0],ch[x][1],pre[x],size[x],rev[x]); Treavel(ch[x][1]); } } void debug() { printf("root:%d\n",root); Treavel(root); } int main() { int q; while(~scanf("%d%d",&n,&q)&&(n>0&&q>0)) { Init(); char op[5]; int a,b,c; while(q--) { //debug(); scanf("%s",op); if(op[0]=='C') { scanf("%d%d%d",&a,&b,&c); cut(a,b,c); } else { scanf("%d%d",&a,&b); Reverse(a,b); } } cnt=0; InOrder(root); } return 0; } // 1 2 3 4 5 6 7 8 // 1 2 6 7 3 4 5 8
- 版权声明:本文基于《知识共享署名-相同方式共享 3.0 中国大陆许可协议》发布,转载请遵循本协议
- 文章链接:http://www.carlstedt.cn/archives/1194 (转载时请注明本文出处及文章链接)
发表评论
快来吐槽一下吧!