给你一个长度为n 的序列(初始值为1到n)。有m 次操作,每次操作有l r 你需要将l 到 r 的数字翻转。然后放到最后
m次操作后输出答案。
代码:
#include<bits/stdc++.h>
using namespace std;
const int inf =0x3f3f3f3f;
struct Node
{
Node *ch[2];
int s,v,flip; // s孩子个数,v 键值 flip 翻转标记
int cmp(int k){
int d=k-ch[0]->s;
if(d==1) return -1; // 该节点就是要找的第k小的节点
return d<=0?0:1; // 确定第k小的节点是在左子树还是右子树
}
void maintain()
{
s=ch[0]->s+ch[1]->s+1; // 也就相当于push_up 更新孩子的个数(包括自己)
}
void push_down()
{
if(flip){
flip=0;
swap(ch[0],ch[1]);
ch[0]->flip=!(ch[0]->flip);
ch[1]->flip=!(ch[1]->flip);
}
}
};
Node *null= new Node(); // 建立一个空的节点 避免 NULL指针的错误。也可以有其他的写法
// 每个叶节点的两个孩纸指针都会连向该节点。可以理解为 访问到叶节点的标志
void rotate(Node* &o,int d) // d 为0表示左旋,为1表示右旋
{
Node* k=o->ch[d^1];
o->ch[d^1]=k->ch[d];
k->ch[d]=o;
o->maintain();
k->maintain();
o=k;
}
void splay(Node* &o,int k) // 找到第k小的并进行旋转操作 使得该节点旋转到根
{
o->push_down(); // 如果有翻转标记 先下放标记
int d=o->cmp(k); //比较在那棵子树中 -1 表示该节点 0 表示左子树 1 表示右子树
if(d==1) k-=(o->ch[0]->s+1); // 右子树中
if(d!=-1){
Node *p=o->ch[d];
p->push_down();
int d2=p->cmp(k);
int k2=(d2==0?k:k-1-p->ch[0]->s);
if(d2!=-1){
splay(p->ch[d2],k2);
if(d==d2) rotate(o,d^1);
else rotate(o->ch[d],d);
}
rotate(o,d^1);
}
}
Node* merge(Node *left,Node *right) //left!=null 合并操作
{
splay(left,left->s); //找到最大的 那么右子树一定为空
left->ch[1]=right; // right 赋给右子树
left->maintain(); //push_up
return left;
}
void split(Node* o,int k,Node* &left,Node* &right) //分离操作
{
splay(o,k);// 找到第k小的 分离操作 左子树不能为空!!!
left=o; //分离
right=o->ch[1]; //分离
o->ch[1]=null;
left->maintain();
}
const int maxn=100000+1000;
struct SplaySequence
{
int n;
Node seq[maxn]; // maxn 个节点
Node *root;
Node* build(int sz)
{
if(sz==0) return null;
Node* L=build(sz/2);
Node* o=&seq[++n];
o->v=n;
o->ch[0]=L;
o->ch[1]=build(sz-sz/2-1);
o->s=o->flip=0;
o->maintain();
return o;
}
void init(int sz)
{
n=0;
null->s=0;
root=build(sz);
}
};
vector< int >ans;
void print(Node *o)
{
if(o!=null){
o->push_down();
print(o->ch[0]);
ans.push_back(o->v);
print(o->ch[1]);
}
}
void debug(Node* o)
{
if(o!=null){
o->push_down();
debug(o->ch[0]);
printf("%d ",o->v-1);
debug(o->ch[1]);
}
}
SplaySequence ss;
// 分离操作,左子树不能为空,所以对于该题来说,我们可以建立一棵
// 叶节点为n+1 的树 ,这样 -1 就是我们要的答案。
int main()
{
int n,m;
scanf("%d %d",&n,&m);
ss.init(n+1);
while(m--)
{
int a,b;
scanf("%d %d",&a,&b);
Node *o,*mid,*left,*right;
split(ss.root,a,left,o);
split(o,b-a+1,mid,right);
mid->flip^=1;
ss.root=merge(merge(left,right),mid);
}
print(ss.root);
for(int i=1;i<ans.size();i++){
printf("%d\n",ans[i]-1);
}
return 0;
}