人生第一个splay题。
区间分裂,区间合并还有区间翻转都是比较裸的板子
一个区间分裂成三个区间还是写一个两两分裂的函数比较好写(
区间合并也是
感觉其他也没有什么要针对这个题说的
如果用动态内存的话建议用数组指针,不然会MLE(窝也不造是不是叫这个)
只要splay写好了就能过
以及代码如下
#include<bits\stdc++.h>
using namespace std;
#define l ch[0]
#define r ch[1]
struct node{
int val,siz;
int flp;
node *ch[2];
void maintain(){
siz=1;
if(ch[0]) siz+=ch[0]->siz;
if(ch[1]) siz+=ch[1]->siz;
}
};
const int maxn = 312345;
node nodes[maxn];
int tot;
int size(node *o){
if(o==NULL){
return 0;
}
return o->siz;
}
void zg(node* &o,int d){
node *k=o->ch[d];
o->ch[d]=k->ch[1^d];
k->ch[1^d]=o;
o=k;
o->ch[1^d]->maintain();
o->maintain();
}
node *newnode(int x){
node * ret = &nodes[tot++];
ret->flp=0;
ret->val = x;
ret->siz = 0;
ret->l=ret->r=NULL;
return ret;
}
void push(node *rot){
rot->flp=0;
swap(rot->l,rot->r);
if(rot->l)
rot->l->flp ^=1;
if(rot->r)
rot->r->flp ^=1;
}
int splay(node* &rot,int x){
if(rot->flp)
push(rot);
if(size(rot->l)+1==x)
return 2;
int d = size(rot->l)+1 > x? 0:1;
if(d) x-=size(rot->l)+1;
int k = splay(rot->ch[d],x);
if(k==2) return d;
if(k==d){
zg(rot,d);zg(rot,d);
}
else{
zg(rot->ch[d],k);zg(rot,d);
}
return 2;
}
void fnd(node* &root,int x){
if(!root)
return;
int k = splay(root,x);
if(k!=2)
zg(root,k);
}
void out(node *rot,int d,int k){
if(rot->r)
out(rot->r,d+1,-1);
for(int i = 0;i<d;i++)
printf(" ");
if(k==0){
printf("--");
}
else{
printf(" ");
if(k==-1)
printf("/");
else
printf("\\");
}
printf("%d(%d)\n",rot->val,rot->siz);
if(rot->l)
out(rot->l,d+1,1);
}
void print(node *rot){
puts("-------------");
if(!rot)
puts("NULL!");
else
out(rot,0,0);
puts("=============");
}
node *splite(node *&rot,int x){
if(x==0){
node *ret = rot;
rot=NULL;
return ret;
}
fnd(rot,x);
node *ret = rot->r;
rot->r=NULL;
rot->maintain();
return ret;
}
node *merg(node* L,node* R){
if(L){
fnd(L,L->siz);
L->r=R;
L->maintain();
return L;
}
if(R){
fnd(R,1);
R->l=L;
R->maintain();
return R;
}
return NULL;
}
void cut(int L,int R,int C,node* &root){
node *right=splite(root,R);
node *left=splite(root,L-1);
swap(left,root);
left=merg(left,right);
right=splite(left,C);
left=merg(left,root);
root=merg(left,right);
}
void flip(int L,int R,node* &root){
node *right=splite(root,R);
node *left=splite(root,L-1);
swap(left,root);
root->flp ^=1 ;
if(left)
root=merg(left,root);
if(right){
fnd(right,1);
right->l=root;
right->maintain();
root=right;
}
}
node *build(int n){
node *root = newnode(1);
root->maintain();
for(int i =2;i<=n;i++){
node *k = newnode(i);
k->l = root;
root = k;
root->maintain();
}
return root;
}
int ans[maxn];
int len;
void mid(node *root){
if(root->flp)
push(root);
if(root->l)
mid(root->l);
ans[len++]=root->val;
if(root->r)
mid(root->r);
}
int main(){
int n,m;
char arr[10];
while(~scanf("%d %d",&n,&m) && (n+1)||(m+1)){
tot=0;
node *root = build(n);
int L,R,C;
while(m--){
scanf("%s %d %d",arr,&L,&R);
if(arr[0]=='C'){
scanf("%d",&C);
cut(L,R,C,root);
// print(root);
}
else{
flip(L,R,root);
// print(root);
}
}
len=0;
mid(root);
for(int i = 0;i<n;i++)
printf(i<n-1?"%d ":"%d\n",ans[i]);
}
return 0;
}
===================================update====================
又写了一发,在右边添加了一个虚拟节点,优化了cut和flip的代码量
node *getseg(int L,int R,node* &root){ //goal is return->l and father is return
L--,R++;
if(L){
fnd(root,L);
fnd(root->r,R-L);
return root->r;
}
else{
fnd(root,R);
return root;
}
}
void flip(node* &root,int L,int R){
node * k = getseg(L,R,root);
k->l->flp ^= 1;
}
void cut(node* &root,int L,int R,int c){
node * fa = getseg(L,R,root);
node * k = fa->l;
fa->l=NULL; fa->maintain();
root->maintain();
if(c){
fnd(root,c);
fnd(root,c+1);
root->l->r=k;
root->l->maintain();
root->maintain();
}
else{
fnd(root,1);
root->l=k;
root->maintain();
}
}