这道题,首先给你一个长度为n的数组,数组的元素为1 - n ,然后给你m次操作。
一共有两种操作,一种是CUT a, b, c 。这种操作就是先截取a - b位置的元素,然后再将他接到位置c的后面。当然这个位置c是截取掉之后的位置。
第二中操作,FLIP a ,b ,就是将a - b 位置的元素反转。
最后输出m次操作之后数组的元素。
这道题可以用Splay tree来写。
对于操作1,我们要对区间[a , b ]进行操作,首先,找出a - 1和b + 1在树中的位置。使用函数get_Kth(int k )
int get_K(int r , int k){//找第K个值
push_down(r) ;
int t = num[ch[r][0]] ;
if(k == t + 1)return r ;
if(k <= t)return get_K(ch[r][0] , k) ;
else return get_K(ch[r][1] , k - t - 1) ;
}
找到a - 1 , b + 1 的位置之后,我们先把a - 1移到树的根节点,然后把b + 1移到根节点的右子树,使用Splay操作。
void Splay(int x ,int s ){//将节点x转到节点s下面
push_down(x) ;
while(fa[x] != s){
if(fa[fa[x]] == s)rotate(x ,ch[fa[x]][0] == x) ;
else {
int y = fa[x] ;
int z = fa[y] ;
int kind = ( ch[z][0] == y );
if(ch[y][kind] == x){
rotate(x ,!kind) ;
rotate(x , kind) ;
}
else {
rotate(y , kind ) ;
rotate(x , kind ) ;
}
}
}
push_up(x) ;
if(s == 0)root = x ;
}
这样操作之后根节点就是a - 1 ,根节点的右子树就是b + 1。这样操作之后,区间[a , b]就到了根节点右子树的左子树上。
这样,我们就可以对区间[a , b 进行删除了,只需将根节点的右子树的左子树设为0即可。
对于将这个区间插入到c节点后面。先找到c节点的位置,然后将c节点移到根节点,然后找到根节点右子树的最小值,将他移到根节点的右子树,然后将区间 [ a , b ] 接到根节点右子树的左子树上,那么 [ a , b ] 区间就在节点c之后了 。这个操作就完成了。
对于操作2,其实更简单,只需要反转区间就可以。我们可以采用上述同样的操作,将a - 1 移到根节点,将b + 1移到根节点的右子树,那么区间[a , b ]就到了根节点右子树的左子树上,我们对这个节点的FLIP进行取异或即可。
CODE:
作为自己的Splay tree 模版,参考了别人的代码。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#define inf 2000000000
#define PI acos(-1.0)
#define Max 1111
#define REP(i,s,t) for (int i = s ;i <= t ; ++ i)
#define PII pair<int,int>
#define clr(a,b) memset(a,b,sizeof(a)) ;
using namespace std;
inline void RD(int &ret) {
char a ;
do {
a = getchar() ;
} while(a < '0' || a > '9') ;
ret = a - '0' ;
while((a = getchar()) && a >= '0' && a <= '9') {
ret = ret * 10 + a - '0' ;
}
}
int ch[1111111][2] , fa[1111111] , data[1111111] , flip[1111111] ;
int num[1111111] ;
int root , tot ;
int cnt , n ;
void newnode(int &x ,int k ,int father){
x = ++ tot ;
ch[x][0] = ch[x][1] = 0 ;
//num[x] = 1 ;
data[x] = k ;
fa[x] = father ;
flip[x] = 0 ;
}
void push_up(int x){
num[x] = num[ch[x][0]] + num[ch[x][1]] + 1 ;
}
void push_down(int x ){
if(flip[x]){
flip[x] = 0 ;
flip[ch[x][0]] ^= 1 ;
flip[ch[x][1]] ^= 1 ;
swap(ch[x][0] ,ch[x][1]) ;
}
}
void build(int &s ,int l ,int r ,int father){
if(l > r)return ;
int mid = l + r >> 1 ;
newnode(s ,mid ,father) ;
build(ch[s][0] , l , mid - 1,s) ;
build(ch[s][1] , mid + 1 ,r ,s) ;
push_up(s) ;
}
void init(){
root = tot = 0 ;
ch[0][0] = ch[0][1] = fa[0] = num[0] = flip[0] = 0 ;
newnode(root, -1 , 0 ) ;
newnode(ch[root][1] ,-1 ,root) ;
num[root] = 2 ;
build(ch[ch[root][1]][0] ,1 ,n ,ch[root][1]) ;
push_up(ch[root][1]) ;
push_up(root) ;
}
void rotate(int x ,int kind){//kind = 0 ,左旋,kind = 1 ,右旋
int y = fa[x] ;
push_down(y) ;
push_down(x) ;
ch[y][!kind] = ch[x][kind] ;
fa[ch[x][kind]] = y ;
if(fa[y])ch[fa[y]][ch[fa[y]][1] == y] = x ;
fa[x] = fa[y] ;
ch[x][kind] = y ;
fa[y] = x ;
push_up(y) ;
}
void Splay(int x ,int s ){//将节点x转到节点s下面
push_down(x) ;
while(fa[x] != s){
if(fa[fa[x]] == s)rotate(x ,ch[fa[x]][0] == x) ;
else {
int y = fa[x] ;
int z = fa[y] ;
int kind = ( ch[z][0] == y );
if(ch[y][kind] == x){
rotate(x ,!kind) ;
rotate(x , kind) ;
}
else {
rotate(y , kind ) ;
rotate(x , kind ) ;
}
}
}
push_up(x) ;
if(s == 0)root = x ;
}
int get_K(int r , int k){//找第K个值
push_down(r) ;
int t = num[ch[r][0]] ;
if(k == t + 1)return r ;
if(k <= t)return get_K(ch[r][0] , k) ;
else return get_K(ch[r][1] , k - t - 1) ;
}
int get_MIN(int r ){//找最小值。
push_down(r) ;
//int x = ch[r][0] ;
while(ch[r][0]) {
r = ch[r][0] ;
push_down(r) ;
}
return r ;
}
int get_MAX(int r){//找最大值。
push_down(r) ;
//int x = ch[r][1] ;
while(ch[r][1]){
r = ch[r][1] ;
push_down(r) ;
}
return r ;
}
int get_pree(int k){//找前驱。本题没有用到
// push_down(k) ;
int now = ch[k][0] ;
while(ch[now][1]){
now = ch[now][1] ;
// push_down(now) ;
}
return now ;
}
int get_next(int k){//找后继。
int now = ch[k][1] ;
while(ch[now][0]){
now = ch[now][0] ;
}
return now ;
}
void rev(int a ,int b){
int x = get_K(root ,a) ;
int y = get_K(root ,b + 2) ;
Splay(x ,0) ;//将x移到根节点。
Splay(y ,root) ;//将y移到根节点下面。成为x的右子树。
flip[ch[ch[root][1]][0]] ^= 1 ;//根节点的右子树的左子树,就是区间a , b 将这个区间的flip取异或。即反转操作。
}
void cut(int a ,int b ,int c){
int x = get_K(root ,a ) ;
int y = get_K(root ,b + 2) ;
Splay(x ,0) ;//将x移到根节点
Splay(y ,root) ;//将y移到根节点下面,成为x的右子树。
int temp = ch[ch[root][1]][0] ;
ch[ch[root][1]][0] = 0 ;//删除a - b 区间
push_up(ch[root][1]) ;
push_up(root) ;
int z = get_K(root , c + 1) ;
//int z = get_next(root) ;
Splay(z ,0) ; //将c移到根节点。
int m = get_MIN(ch[root][1] ) ;//根节点右子树的最小值。
//int m = get_next(root) ;
Splay( m ,root ) ;//将m移到根节点下。
ch[ch[root][1]][0] = temp ;//将a - b 区间接上。
fa[ch[ch[root][1]][0]] = ch[root][1] ;
push_up(ch[root][1]) ;
push_up(root) ;
}
void order(int x){
if(!x)return ;
push_down(x) ;
order(ch[x][0]) ;
if(cnt >= 1 && cnt <= n){
if(cnt > 1)cout <<' ' ;
printf("%d",data[x]) ;
}
cnt ++ ;
order(ch[x][1]) ;
}
char str[1111] ;
int main() {
int op ;
while(cin >> n >> op){
if( n == -1 && op == -1)break ;
init() ;
REP(i, 0, op - 1){
cin >> str ;
if(str[0] == 'C'){
int a , b , c ;
RD(a) ;RD(b) ;RD(c) ;
cut(a, b , c ) ;
}else {
int a ,b ;
RD(a) ;RD(b) ;
rev(a , b) ;
}
}
cnt = 0 ;
order(root) ;
cout << endl;
}
return 0;
}