题解 P3391 【【模板】文艺平衡树(Splay)】
Fatalis_Lights · · 题解
Solution
->题面:(模拟+离线问询) 一维序列折腾问题系列
暴力算法:O(nm)
自然是平衡树来解答。。。(废话)
维护中序遍历是当前序列
int build(int l,int r){
if (l==r) return s[l]=1,l;
int m=(l+r)>>1;
if (m-1>=l) ch[m][0]=build(l,m-1);
if (m+1<=r) ch[m][1]=build(m+1,r);
//这里不是线段树哦qwq
s[m]=r-l+1;
return m;
}
//先建一棵初始树好了。
//这个题只有翻转操作,所以不需要维护重数之类的。
->如果翻转的是完整子树,只要对称就好(左右儿子互换)
->如果翻转非完整子树,设位[L,R];
STEP1. 将L-1向上旋转到根节点
STEP2: 将R+1向上连续旋转到根的右儿子
->此时[L,R]被调整到同一棵子树上(根节点的左右孙子)
void rotateKth(int k,int x,int &p,bool toRt) {
if (rev[x]) flip(x);
if (k==s[ch[x][0]]+1) return;
int d=k>(s[ch[x][0]]+1);
rotateKth(k-d*(s[ch[x][0]]+1),ch[x][d],ch[x][d],toRt);
if (toRt || x!=rt) p=rotate(x,d^1);
}
//将中序遍历k号元素一顿操作,toRt=1表示旋转到根,=0表示到根的(右)儿子
//先找k号元素,然后往子树里找,回溯时每次向上旋转
->如何旋转完整子树:直接对称,复杂度O(n)
如果子树没有被查询到...那么不需要翻转(有点像线段树QWQ)
rt=build(1,n+2);
for (int i=1,l,r;i<=m;i++) {
cin>>l>>r,l++,r++;
if (l==r) continue;
rotateKth(l-1,rt,rt,true);
rotateKth(r+1,rt,rt,false);
rev[ch[ch[rt][1]][0]]^=1;
}
print(rt); cout<<endl;
void flip(int x) {
swap(ch[x][0],ch[x][1]);
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
rev[x]^=1;
}
void print(int x) {
if (rev[x]) flip(x);
if (ch[x][0]) print(ch[x][0]);
if (x>=2 && x<=n+1) cout<<x-1<<" ";
if (ch[x][1]) print(ch[x][1]);
}
完整代码:
// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
const int N=100009;
int m,n,tot=1,rt=1,ch[N][2],s[N],rev[N];
int rotate(int o,int d) {
int k=ch[o][d^1];
ch[o][d^1]=ch[k][d];
ch[k][d]=o;
s[o]=1+s[ch[o][0]]+s[ch[o][1]];
s[k]=1+s[ch[k][0]]+s[ch[k][1]];
return k;
}
int build(int l,int r){
if (l==r) return s[l]=1,l;
int m=(l+r)>>1;
if (m-1>=l) ch[m][0]=build(l,m-1);
if (m+1<=r) ch[m][1]=build(m+1,r);
s[m]=r-l+1;
return m;
}
void flip(int x) {
swap(ch[x][0],ch[x][1]);
rev[ch[x][0]]^=1;
rev[ch[x][1]]^=1;
rev[x]^=1;
}
void print(int x) {
if (rev[x]) flip(x);
if (ch[x][0]) print(ch[x][0]);
if (x>=2 && x<=n+1) cout<<x-1<<" ";
if (ch[x][1]) print(ch[x][1]);
}
void rotateKth(int k,int x,int &p,bool toRt) {
if (rev[x]) flip(x);
if (k==s[ch[x][0]]+1) return;
int d=k>(s[ch[x][0]]+1);
rotateKth(k-d*(s[ch[x][0]]+1),ch[x][d],ch[x][d],toRt);
if (toRt || x!=rt) p=rotate(x,d^1);
}
int main(){
cin>>n>>m;
rt=build(1,n+2);
for (int i=1,l,r;i<=m;i++) {
cin>>l>>r,l++,r++;
if (l==r) continue;
rotateKth(l-1,rt,rt,true);
rotateKth(r+1,rt,rt,false);
rev[ch[ch[rt][1]][0]]^=1;
}
print(rt); cout<<endl;
return 0;
}
AC记录: qwqwq