HDU-3487 Play with Chain Splay tee区间反转,移动

时间:2023-03-08 15:56:18

  题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3487

  对于一个数列有两种操作:1.CUT a b c,先取出a-b区间的数,然后把它们放在取出后的第c个数后面。2.FLIP a b,把区间a-b的数反转。对于第一个操作,进行两次区间移动,第a-1个数Splay到根节点,b+1个数Splay到root的右儿子,ch[ch[root][1]][0]则表示那个区间,然后把它们除掉,然后在移动区间,把第c个数Splay到root,第c+1个数Splay到root的右儿子,再把刚才的区间加上即可。第二次操作每个节点标价一下,表示他的儿子是否反转,用懒惰操作标记延迟更新。。。

 //STATUS:C++_AC_578MS_6452KB
#include <functional>
#include <algorithm>
#include <iostream>
//#include <ext/rope>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
//using namespace __gnu_cxx;
//define
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1.0)
//typedef
typedef __int64 LL;
typedef unsigned __int64 ULL;
//const
const int N=;
const int INF=0x3f3f3f3f;
const int MOD=,STA=;
const LL LNF=1LL<<;
const double EPS=1e-;
const double OO=1e15;
const int dx[]={-,,,};
const int dy[]={,,,-};
const int day[]={,,,,,,,,,,,,};
//Daily Use ...
inline int sign(double x){return (x>EPS)-(x<-EPS);}
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
//End #define Key_value ch[ch[root][1]][0]
int pre[N],ch[N][]; //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
int sz[N],st[N]; //子树规模,内存池
int root,tot,top; //根节点,根节点数量,内存池容量
//题目特定数目
int key[N];
bool rev[N];
int n,m;
//debug部分copy from hh
void Treaval(int x) {
if(x) {
Treaval(ch[x][]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d rev = %2d key = %2d\n",x,ch[x][],ch[x][],pre[x],sz[x],rev[x],key[x]);
Treaval(ch[x][]);
}
}
void debug() {printf("%d\n",root);Treaval(root);}
//以上Debug
//新建一个结点
void NewNode(int &x,int fa,int k)
{
if(top)x=st[--top];
else x=++tot;
key[x]=k;
pre[x]=fa;
sz[x]=;
rev[x]=;
ch[x][]=ch[x][]=; //左右孩子为空
} void Push_Up(int x)
{
sz[x]=sz[ch[x][]]+sz[ch[x][]]+;
} void Push_Down(int x)
{
if(rev[x]){
rev[ch[x][]]^=;
rev[ch[x][]]^=;
swap(ch[x][],ch[x][]);
rev[x]=;
}
}
//旋转,kind为1为右旋,kind为0为左旋
void Rotate(int x,int kind)
{
int y=pre[x],z=pre[y];
Push_Down(y);
Push_Down(x); //先把y的标记向下传递,再把x的标记往下传递
//类似SBT,要把其中一个分支先给父节点
ch[y][!kind]=ch[x][kind];
pre[ch[x][kind]]=y;
//如果父节点不是根结点,则要和父节点的父节点连接起来
if(z)ch[z][ch[z][]==y]=x;
pre[x]=z;
ch[x][kind]=y;
pre[y]=x;
Push_Up(y); //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可
}
//Splay调整,将根为r的子树调整为goal
void Splay(int x,int goal)
{
int y,z,kind;
while(pre[x]!=goal){
//父节点即是目标位置,goal为0表示,父节点就是根结点
y=pre[x];
Push_Down(pre[y]);Push_Down(y);Push_Down(x); //设计到反转操作,要先更新,然后在判断!!
if(pre[y]==goal){
Rotate(x,ch[y][]==x);
}
else {
kind=ch[pre[y]][]==y;
//两个方向不同,则先左旋再右旋
if(ch[y][kind]==x){
Rotate(x,!kind);
Rotate(x,kind);
}
//两个方向相同,相同方向连续两次
else {
Rotate(y,kind);
Rotate(x,kind);
}
}
}
//更新根结点
Push_Up(x);
if(goal==)root=x;
} void RotateTo(int k,int goal)
{
int x=root;
Push_Down(x);
while(sz[ch[x][]]!=k){
if(sz[ch[x][]]>k)
x=ch[x][];
else {
k-=sz[ch[x][]]+;
x=ch[x][];
}
Push_Down(x);
}
Splay(x,goal);
}
//建树,中间结点先建立,然后分别对区间两端在左右子树建立
void BuildTree(int &x,int l,int r,int fa)
{
if(l>r)return;
int mid=(l+r)>>;
NewNode(x,fa,mid);
BuildTree(ch[x][],l,mid-,x);
BuildTree(ch[x][],mid+,r,x);
Push_Up(x);
} void Init()
{
root=top=tot=;
ch[][]=ch[][]=sz[]=pre[]=rev[]=; NewNode(root,,-);
NewNode(ch[root][],root,-);
BuildTree(Key_value,,n,ch[root][]);
Push_Up(ch[root][]);
Push_Up(root);
} int ok;
void print(int u)
{
if(!u)return;
Push_Down(u);
print(ch[u][]);
if(key[u]>){
if(ok){printf("%d",key[u]);ok=;}
else printf(" %d",key[u]);
}
print(ch[u][]);
} void Cut(int a,int b,int c)
{
RotateTo(a-,);
RotateTo(b+,root);
int s=Key_value;
Key_value=;
Splay(ch[root][],);
RotateTo(c,);
RotateTo(c+,root);
Key_value=s;
pre[s]=ch[root][];
Splay(Key_value,);
} void Flip(int a,int b)
{
RotateTo(a-,);
RotateTo(b+,root);
rev[Key_value]^=;
} int main()
{
// freopen("in.txt","r",stdin);
int i,j,a,b,c;
char s[];
while(~scanf("%d%d",&n,&m) && (n>= || m>=))
{
if(n==){
printf("1\n");
continue;
}
Init();
while(m--){
scanf("%s",s);
if(s[]=='C'){
scanf("%d%d%d",&a,&b,&c);
Cut(a,b,c);
}
else {
scanf("%d%d",&a,&b);
Flip(a,b);
}
}
ok=;
print(root);
putchar('\n');
}
return ;
}