题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1
分析
- 按数列的顺序建立一颗Splay
对此,既可以直接一个个地插入,又可以用类似线段树的方法,直接递归构建一颗比较平衡的Splay
- 对于区间的翻转操作,可以参考线段树的lazy-tag。
若要翻转区间[l,r](不只是翻转,区间操作都差不多)
- 首先找到第l-1的点与r+1的点。
- 将l-1移至root,r+1移至root(l-1)的右儿子
- 此时,root的右儿子的左儿子即为区间[l,r]
- 将区间翻转(swap左右子树),并加标记
PS:为了方便处理,最好在数列的首尾分别加入一个节点(下文代码为0, n + 1)
代码
using namespace std;
IL int read()
{
int k = 1;
int sum = 0;
char c = getchar();
for(; '0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(; '0' <= c && c <= '9'; c = getchar())
sum =sum * 10 + c - '0';
return sum*k;
}
struct node
{
node *father;
node *son[2];
int val;
int size;
bool lazy;
IL node(int v = 0, node *f = 0)
{
father = f;
son[0] = son[1] = 0;
val = v;
lazy = 0;
size = 1;
}
};
node *root;
int n, m;
IL void clean(node *p)
{
if(!p->lazy) return ;
swap(p->son[0], p->son[1]);
if(p->son[0]) p->son[0]->lazy ^= 1;
if(p->son[1]) p->son[1]->lazy ^= 1;
p->lazy ^= 1;
}
IL bool son(node *f, node *p)
{
return f ? (f->son[1] == p) : -1;
}
IL int size(node *p)
{
return p ? p->size : 0;
}
IL void updata(node *p)
{
p->size = size(p->son[0]) + size(p->son[1]) + 1;
}
IL void connect(node *f, node *p,int k)
{
if(!f) root = p; else f->son[k] = p;
if(p) p->father = f;
}
IL void rotate(node *p)
{
node *f = p->father, *g = f->father;
int x = son(f, p), y = !x;
connect(f, p->son[y], x);
connect(g, p, son(g, f));
connect(p, f, y);
updata(f);
}
IL void splay(node *p, node *q)
{
for(node *f, *g; p->father != q;)
{
f = p->father;
g = f->father;
if(g == q) rotate(p); else
{
if(son(g, f) ^ son(f, p))
rotate(p), rotate(p);
else
rotate(f), rotate(p);
}
}
updata(p);
}
IL node *refind(int t)
{
for(node *p = root; p;)
{
clean(p);
if(t == size(p->son[0]) + 1)
return p;
if(t <= size(p->son[0]))
p = p->son[0];
else
{
t -= size(p->son[0]) + 1;
p = p->son[1];
}
}
}
IL void rever(int x, int y)
{
node *p1 = refind(x), *p2 = refind(y);
splay(p1, 0); splay(p2, p1);
p2->son[0]->lazy ^= 1;
}
IL void build(int l, int r, node *f,int k)
{
int mid = (l + r) >> 1;
node *p = new node(mid, f);
if(!f) root = p; else { f->son[k] = p; }
if(l <= mid - 1) build(l, mid - 1, p, 0);
//if(f) printf("%d %d %d\n", f->val, k, mid);
if(mid + 1 <= r) build(mid + 1, r, p, 1);
updata(p);
}
IL void write(node *p)
{
clean(p);
if(p->son[0]) write(p->son[0]);
if((p->val != 0) && (p->val != n+1)) printf("%d ",p->val);
if(p->son[1]) write(p->son[1]);
}
int main()
{
n = read();
m = read();
build(0, n + 1, 0, 0);
for(int i = 1, x, y; i <= m ; ++ i)
{
x = read() + 1;
y = read() + 1;
rever(x - 1, y + 1);
}
write(root);
return 0;
}