哪个压行鬼才整出来的阴间亚行代码
链接
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010;
int n,m;
struct node{
int s[2];//储存两个儿子
int p;//父节点
int v;//编号
int size;//子树大小
int flag;//有无翻转
int init(int _v,int _p){
v=_v,p=_p;
size=1;
}
}tr[N];
int root;//根节点
int idx;// 动态分配的空间的指针
void pushup(int x){//向上传递
tr[x].size=tr[tr[x].s[0]].size+tr[tr[x].s[1]].size+1;//左儿子加右儿子加根节点
}
void pushdown(int x){
if(tr[x].flag){//如果x是需要翻转的
swap(tr[x].s[0],tr[x].s[1]);//翻转一下左右儿子
tr[tr[x].s[0]].flag^=1;//向下传左右儿子的标记
tr[tr[x].s[1]].flag^=1;
tr[x].flag=0;
}
}
void rotate(int x){//旋转操作
int y=tr[x].p;//x的父节点
int z=tr[y].p;//y的父节点
int k=tr[y].s[1]==x;//用k判断x是y的左儿子还是右儿子
// k=0 x是y的左儿子 k=1 x是y的右儿子
tr[z].s[tr[z].s[1]==y]=x,tr[x].p=z;//将z的儿子变成x,把x的父节点变成z
//利用tr[z].s[1]==y就不需要判定是左旋还是右旋
//如果z的右儿子是y,那么右儿子就变成x,否者左儿子变成x
tr[y].s[k]=tr[x].s[k^1];//y的左儿子变成x的右儿子
tr[tr[x].s[k^1]].p=y;//x的右(左)儿子的父节点等于y
tr[x].s[k^1]=y;
//x的右(左)儿子变成y
tr[y].p=x;//y的父节点变成x
pushup(y),pushup(x);
}
void splay(int x,int k){
while(tr[x].p!=k){//只要x的父节点不是k
int y=tr[x].p,z=tr[y].p;
if(z!=k){
if((tr[y].s[1]==x)^(tr[z].s[1]==y)){//只要是折线关系(一个左一个右)
rotate(x);//转x
}else {//如果是直线关系
rotate(y);
}
}
rotate(x);//最后还需要转x(保证中序排列)
}
if(!k)root=x;//如果k是源,就把源点让给x
}
void output(int u){//每次想要访问其儿子,就要把根节点的懒标记往下传
pushdown(u);
if(tr[u].s[0])output(tr[u].s[0]);//有左儿子就先递归输出左儿子
if(tr[u].v>=1&&tr[u].v<=n)cout<<tr[u].v<<" ";//如果当前点不是哨兵就输出当前点
if(tr[u].s[1])output(tr[u].s[1]);//接下来递归右儿子
}
void insert(int v){
int u=root,p=0;
while(u){//求x应该插到哪个点
p=u,u=tr[u].s[v>tr[u].v];//如果传参v是u的左儿子就会返回0
}
u=++idx;//给u新分配一个点
if(p){//如果u有父节点,父节点就要更新儿子信息
tr[p].s[v>tr[p].v]=u;
}
tr[u].init(v,p);//初始化u
splay(u,0);
}
int get_k(int k){//找第k个数
int u=root;
while(1){
pushdown(u);//把信息传下去
if(tr[tr[u].s[0]].size>=k)u=tr[u].s[0];//如果左子树的点数大于k,说明k在右边
else if(tr[tr[u].s[0]].size+1==k){//如果左子树点数恰好等等于k,说明正好在这个点
return u;
}else{
k-=tr[tr[u].s[0]].size+1,u=tr[u].s[1];//k减去左边这些点的数量,再到右子树中去找
}
}
return -1;
}
int main(){
cin>>n>>m;
for(int i=0;i<=n+1;i++){//加两个哨兵
insert(i);
}
while(m--){
int l,r;
cin>>l>>r;//由于加了哨兵,下标要变
l=get_k(l),r=get_k(r+2);
splay(l,0),splay(r,l);//把左端点转到根,右端点转到根的下面
tr[tr[r].s[0]].flag^=1;//把r的左子树整个翻转一遍
}
output(root);//输出中序遍历
return 0;
}