调了差不多一天的splay终于把splay写对了
顺便纠正了一些原来的错误
但是喵喵喵idy002学长的板子似乎是惰性修改可能会有错。。
Splay写了两个部分
第一个是区间反转,比较简单,比较好写,在find的时候pushdown翻转标记即可
第二个就是普通平衡树,耗了我一天下午
找前驱和后继终于学到了方便的方法
前驱 int pos=T.rank(x) pre=T.kth(pos-1);
后继 int pos=T.rank(x+1) suf=T.kth(pos);
贴代码溜了。
bzoj3224
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int n,root,cnt;
struct Splay {
int fa[maxn],son[maxn][2],size[maxn],key[maxn];
void update(int nd) {
size[nd]=size[son[nd][0]]+size[son[nd][1]]+1;
}
void rotate(int nd,int d) {
int baba=fa[nd];
int s=son[nd][!d];
int ss=son[s][d];
son[nd][!d]=ss;
son[s][d]=nd;
son[baba][nd==son[baba][1]]=s;
if (!baba) {
root=s;
}
fa[nd]=s;
fa[s]=baba;
if (ss) {
fa[ss]=nd;
}
update(nd);
update(s);
}
void splay(int nd,int goal) {
while (fa[nd]!=goal) {
int baba=fa[nd];
int pd1=nd==son[baba][0];
if (fa[baba]==goal) {
rotate(baba,pd1);
} else {
int yeye=fa[baba];
int pd2=baba==son[yeye][0];
if (pd1==pd2) {
rotate(yeye,pd2);
rotate(baba,pd1);
} else {
rotate(baba,pd1);
rotate(yeye,pd2);
}
}
}
}
int newnode(int f,int val) {
int nd=++cnt;
fa[nd]=f;
key[nd]=val;
size[nd]=1;
son[nd][0]=son[nd][1]=0;
return nd;
}
void insert(int num) {
if (!root) {
root=newnode(0,num);
return ;
}
int nd=root;
while (son[nd][num>key[nd]]) {
nd=son[nd][num>key[nd]];
}
son[nd][num>key[nd]]=newnode(nd,num);
update(nd);
splay(nd,0);
}
int find(int num) {
int nd=root;
while (key[nd]!=num) {
nd=son[nd][num>key[nd]];
}
splay(nd,0);
return nd;
}
void del(int num) {
int nd=find(num);
int lnd=son[nd][0];
int rnd=son[nd][1];
if (!lnd&&!rnd) {
root=0;
} else if (!lnd) {
root=rnd;
fa[rnd]=0;
} else if (!rnd) {
root=lnd;
fa[lnd]=0;
} else {
while (son[lnd][1]) lnd=son[lnd][1];
while (son[rnd][0]) rnd=son[rnd][0];
splay(lnd,0);
splay(rnd,lnd);
son[rnd][0]=0;
update(rnd);
update(lnd);
}
}
int kth(int k) {
int nd=root;
while (1) {
int ls=size[son[nd][0]];
if (k<=ls) {
nd=son[nd][0];
} else if (k>=ls+2){
nd=son[nd][1];
k-=(ls+1);
} else {
splay(nd,0);
return key[nd];
}
}
}
int rank(int num) {
int nd=root;
int rt=1;
int last;
while (nd) {
last=nd;
if (key[nd]<num) {
rt+=size[son[nd][0]]+1;
nd=son[nd][1];
} else {
nd=son[nd][0];
}
}
splay(last,0);
return rt;
}
}T;
int main() {
scanf("%d",&n);
for (int i=1;i<=n;i++) {
int opt,x;
scanf("%d%d",&opt,&x);
if (opt==1) {
T.insert(x);
} else if (opt==2) {
T.del(x);
} else if (opt==3) {
printf("%d\n",T.rank(x));
} else if (opt==4) {
printf("%d\n",T.kth(x));
} else if (opt==5) {
int pos=T.rank(x);
printf("%d\n",T.kth(pos-1));
} else {
int pos=T.rank(x+1);
printf("%d\n",T.kth(pos));
}
}
return 0;
}
bzoj3223
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=1e5+5;
int root;
int n,m;
struct Splay {
int rev[maxn],size[maxn],fa[maxn],son[maxn][2];
void update(int nd) {
size[nd]=size[son[nd][1]]+size[son[nd][0]]+1;
}
int build(int f,int lf,int rg) {
if (lf>rg) return 0;
int mid=(lf+rg)>>1;
fa[mid]=f;
son[mid][0]=build(mid,lf,mid-1);
son[mid][1]=build(mid,mid+1,rg);
update(mid);
return mid;
}
void init() {
root=build(0,1,n+2);
}
void pushdown(int nd) {
if (rev[nd]) {
swap(son[nd][1],son[nd][0]);
if (son[nd][0]) rev[son[nd][0]]^=1;
if (son[nd][1]) rev[son[nd][1]]^=1;
rev[nd]=0;
}
}
void rotate(int nd,int d) {
int baba=fa[nd];
int s=son[nd][!d];
int ss=son[s][d];
son[s][d]=nd;
son[nd][!d]=ss;
son[baba][nd==son[baba][1]]=s;
if (!baba) {
root=s;
}
fa[nd]=s;
fa[s]=baba;
if (ss) {
fa[ss]=nd;
}
update(nd);
update(s);
}
void splay(int nd,int goal) {
while (fa[nd]!=goal) {
int baba=fa[nd];
int pd1=nd==son[baba][0];
if (fa[baba]==goal) {
rotate(baba,pd1);
} else {
int yeye=fa[baba];
int pd2=baba==son[yeye][0];
if (pd1==pd2) {
rotate(yeye,pd2);
rotate(baba,pd1);
} else {
rotate(baba,pd1);
rotate(yeye,pd2);
}
}
}
}
int find(int pos) {
int nd=root;
while (1) {
pushdown(nd);
int ls=size[son[nd][0]];
if (pos<=ls) {
nd=son[nd][0];
} else if (pos>=ls+2) {
nd=son[nd][1];
pos-=(ls+1);
} else {
splay(nd,0);
return nd;
}
}
}
void reverse(int lf,int rg) {
int lnd=find(lf-1);
int rnd=find(rg+1);
splay(lnd,0);
splay(rnd,lnd);
rev[son[rnd][0]]^=1;
splay(rnd,0);
}
}T;
int main(){
scanf("%d%d",&n,&m);
T.init();
for (int i=1;i<=m;i++) {
int lf,rg;
scanf("%d%d",&lf,&rg);
T.reverse(lf+1,rg+1);
}
for (int i=2;i<=n+1;i++) {
printf("%d ",T.find(i)-1);
}
return 0;
}
这个中序遍历是nlogn的,似乎听说可以n的直接跑,不过感觉不可行。逃之夭夭。。。。。。。