P3391 文艺平衡树
题目描述
维护序列, 有若干翻转操作, 输出最后序列
Solution
带翻转标记的平衡树模板
在翻转时, 查询第L-1大, 和R+1大的元素 (此时下标为权值)
( 考虑到交换左右子树对查找树性质的影响, 所以不能直接查询前驱后继 )
在操作, 和查询大操作下传标记即可
因为每个元素固定只有一个, 所以不用开cnt数组
输出时直接输出中序遍历即可
Code
#include<bits/stdc++.h>
#define reg register
const int maxn = 100005;
int N, M, node_num, rot;
int ch[maxn][2];
int key[maxn], par[maxn], tag[maxn], size[maxn];
inline int chk(int x){ return ch[par[x]][1] == x; }
void push_down(int k){
tag[k] = 0;
std::swap(ch[k][0], ch[k][1]);
tag[ch[k][0]] ^= 1, tag[ch[k][1]] ^= 1;
}
inline void push_up(int k){ size[k] = size[ch[k][0]] + size[ch[k][1]] + 1; }
void rotate(int x){
int fa = par[x], gra = par[fa], son = ch[x][chk(x)^1], dir = chk(x);
if(tag[fa]) push_down(fa);
if(tag[x]) push_down(x);
ch[fa][dir] = son, par[son] = fa;
ch[gra][chk(fa)] = x, par[x] = gra;
ch[x][dir^1] = fa, par[fa] = x;
push_up(fa), push_up(x);
}
void Splay(int x, int aim = 0){
while(par[x] != aim){
int fa = par[x], gra = par[fa];
if(gra != aim){ //sign
if(chk(x) == chk(fa)) rotate(fa);
else rotate(x);
}
rotate(x);
}
if(!aim) rot = x;
}
void Insert(int x){
int cur = rot, last = 0;
while(cur) last = cur, cur = ch[cur][key[cur]<x];
cur = ++ node_num;
if(last) ch[last][key[last]<x] = cur; //sign
ch[cur][0] = ch[cur][1] = 0;
key[cur] = x, par[cur] = last;
size[cur] = 1;
Splay(cur);
}
void find(int x){
if(!rot) return ;
int cur = rot;
while(ch[cur][key[cur]<x] && key[cur] != x) cur = ch[cur][key[cur]<x];
Splay(cur); //sign
}
int S_pre(int x, short opt){
find(x);
int cur = ch[rot][opt]; opt ^= 1;
while(ch[cur][opt]) cur = ch[cur][opt];
return cur;
}
int Kth(int k, int tmp){
if(tag[k]) push_down(k);
if(size[ch[k][0]] >= tmp) return Kth(ch[k][0], tmp);
if(tmp > size[ch[k][0]] + 1){
tmp -= size[ch[k][0]] + 1;
return Kth(ch[k][1], tmp);
}
return k;
}
void Reverse(int l, int r){
// int L = S_pre(l, 0), R = S_pre(r, 1);
int L = Kth(rot, l), R = Kth(rot, r+2);
// printf("L: %d R: %d
", key[L], key[R]);
Splay(L), Splay(R, L);
int k = ch[R][0];
tag[k] ^= 1;
}
void print(int k){
if(!k) return ;
if(tag[k]) push_down(k);
print(ch[k][0]);
if(key[k] >= 1 && key[k] <= N) printf("%d ", key[k]);
print(ch[k][1]);
}
int main(){
scanf("%d%d", &N, &M);
Insert(N+1), Insert(0);
for(reg int i = 1; i <= N; i ++) Insert(i);
int L, R;
// printf("%d
", size[rot]);
while(M --){
scanf("%d%d", &L, &R);
Reverse(L, R);
}
print(rot);
return 0;
}