对区间[1,n]执行m条指令。
指令[a,b]表示取出第a~b元素翻转并放入队列尾部。
Splay的构造参考《运用伸展树解决数列维护问题》
具体代码的编写参考了NOI 2005 维护数列-BYVoid
-----------------
/**
Splay Tree 索引
Node:
void addIt(int ad) 区间添加ad
void revIt() 区间翻转
void upd() 更新结点,子树改变后使用
void pushdown() 向下传递懒惰标记
Splay:
Node* newNode(int v,Node* f) 构造一个val值为v的节点,父节点为f,
Node* build(int l,int r,Node* f) 构造区间[l,r],父节点为f;
void rotate(Node* t,int d) 左旋右旋
void splay(Node* t,Node* f) 将结点t伸展到f
void select(int k) 返回第k个节点并伸展到f,不计虚拟结点
Node*&get(int l, int r) 返回区间[l,r],即l-1旋转到根,r+1旋转到根的右儿子
void reverse(int l,int r) 翻转区间[l,r]
void split(int l,int r,Node*&s1) 将区间[l,r]剪切到s1
void cut(int l,int r) 将区间[l,r]剪切到序列尾部
void init(int n) 构造区间[1,n]并初始化
void show(Node* rt) 输出树rt的中序遍历,debug用
void output(int l,int r) 输出并伸展区间[l,r],复杂度较高待优化
**/
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int MAX_N = 150000 + 10;
const int INF = ~0U >> 1;
struct Node{
Node *ch[2],*pre;//左右子树,父节点
int val;//关键字
int size;//以它为根的子树的总结点数
int mx;//最大值
int add;//添加标记
bool rev;//翻转标记
Node(){
size=0;
val=mx=-INF;
add=0;
}
void addIt(int ad){
add+=ad;
mx+=ad;
val+=ad;
}
void revIt(){
rev^=1;
}
void upd(){
size=ch[0]->size+ch[1]->size+1;
mx=max(val,max(ch[0]->mx,ch[1]->mx));
}
void pushdown();
}Tnull,*null=&Tnull;
void Node::pushdown(){
if (add!=0){
for (int i=0;i<2;++i)
if (ch[i]!=null) ch[i]->addIt(add);
add = 0;
}
if (rev){
swap(ch[0],ch[1]);
for (int i=0;i<2;i++)
if (ch[i]!=null) ch[i]->revIt();
rev = 0;
}
}
struct Splay{
Node nodePool[MAX_N],*cur;//内存分配
Node* root;//根
Splay(){
cur=nodePool;
root=null;
}
//清空内存,init()调用
void clear(){
cur=nodePool;
root=null;
}
//新建节点,build()用
Node* newNode(int v,Node* f){
cur->ch[0]=cur->ch[1]=null;
cur->size=1;
cur->val=v;
cur->mx=v;
cur->add=0;
cur->rev=0;
cur->pre=f;
return cur++;
}
//构造区间[l,r]中点m,init()使用
Node* build(int l,int r,Node* f){
if(l>r) return null;
int m=(l+r)>>1;
Node* t=newNode(m,f);
t->ch[0]=build(l,m-1,t);
t->ch[1]=build(m+1,r,t);
t->upd();
return t;
}
//旋转操作,c=0表示左旋,c=1表示右旋
void rotate(Node* x,int c){
Node* y=x->pre;
y->pushdown();
x->pushdown();
//先将y结点的标记向下传递(因为y在上面)
y->ch[!c]=x->ch[c];
if (x->ch[c]!=null) x->ch[c]->pre=y;
x->pre=y->pre;
if (y->pre!=null)
{
if (y->pre->ch[0]==y) y->pre->ch[0]=x;
else y->pre->ch[1]=x;
}
x->ch[c]=y;
y->pre=x;
y->upd();//维护y结点
if (y==root) root=x;
}
//Splay操作,表示把结点x转到结点f的下面
void splay(Node* x,Node* f){
x->pushdown();//下传x的标记
while (x->pre!=f){
if (x->pre->pre==f){//父节点的父亲为f,执行单旋
if (x->pre->ch[0]==x) rotate(x,1);
else rotate(x,0);
}else{
Node *y=x->pre,*z=y->pre;
if (z->ch[0]==y){
if (y->ch[0]==x) rotate(y,1),rotate(x,1);//一字型旋转
else rotate(x,0),rotate(x,1);//之字形旋转
}else{
if (y->ch[1]==x) rotate(y,0),rotate(x,0);//一字型旋转
else rotate(x,1),rotate(x,0);//之字形旋转
}
}
}
x->upd();//最后再维护X结点
}
//找到处在中序遍历第k个结点,并将其旋转到结点f的下面
void select(int k,Node* f){
int tmp;
Node* x=root;
x->pushdown();
k++;//空出虚拟节点
for(;;){
x->pushdown();
tmp=x->ch[0]->size;
if (k==tmp+1) break;
if (k<=tmp) x=x->ch[0];
else{
k-=tmp+1;
x=x->ch[1];
}
}
splay(x,f);
}
//选择[l,r]
Node*&get(int l, int r){
select(l-1,null);
select(r+1,root);
return root->ch[1]->ch[0];
}
//翻转[l,r]
void reverse(int l,int r){
Node* o=get(l,r);
o->rev^=1;
splay(o,null);
}
//剪切出[l,r]到s1
void split(int l,int r,Node*&s1)
{
Node* tmp=get(l,r);
root->ch[1]->ch[0]=null;
root->ch[1]->upd();
root->upd();
s1=tmp;
}
void cut(int l,int r)
{
Node* tmp;
split(l,r,tmp);
select(root->size-1,null);
select(root->size-2,root);
root->ch[0]->ch[1]=tmp;
tmp->pre=root->ch[0];
root->ch[0]->upd();
root->upd();
}
//初始化
void init(int n){
clear();
root=newNode(0,null);
root->ch[1]=newNode(n+1,root);
root->ch[1]->ch[0]=build(1,n,root->ch[1]);
root->upd();
}
//输出中序遍历,debug用
void show(Node* rt){
if (rt==null) return;
if (rt->ch[0]!=null) show(rt->ch[0]);
cerr<<"rt="<<rt->val;
if (rt->ch[0]!=null) cerr<<" l="<<rt->ch[0]->val;
if (rt->ch[1]!=null) cerr<<" r="<<rt->ch[1]->val;
if (rt->pre !=null) cerr<<" pre="<<rt->pre->val;
cerr<<endl;
if (rt->ch[1]!=null) show(rt->ch[1]);
}
//按序输出
void output(int l,int r){
for (int i=l;i<=r;i++){
select(i,null);
cout<<root->val<<endl;
}
//cout<<endl;
}
}T;
int main()
{
int n,m,a,b;
while (~scanf("%d%d",&n,&m))
{
T.init(n);
while (m--)
{
scanf("%d%d",&a,&b);
if (b<a) swap(a,b);
T.reverse(a,b);
T.cut(a,b);
}
T.output(1,n);
}
return 0;
}