P3391 【模板】文艺平衡树
知识点: 平衡树
原题面
题目要求
维护一数列,序列中第 \(i\) 项初始为 \(i\)。
支持区间翻转操作,输出多次翻转后的序列。
分析题意
使被操作序列置于一棵完整的子树中。
通过在 子树根打标记实现区间操作。
Splay 和 Treap 将序列旋转至一棵子树中,
Fhq-Treap 将序列分裂至一棵子树中。
代码实现
Splay
//Splay
#include <cstdio>
#include <ctype.h>
#include <algorithm>
#define min std::min
#define max std::max
#define ll long long
#define Fat (t[now].Fa)
#define ls (t[now].Son[0])
#define rs (t[now].Son[1])
const int MARX = 1e6 + 10;
const int INF = 1e9 + 2077;
//=============================================================
struct SplayNode
{
int Fa, Son[2];
int Val, Size, Cnt;
bool tag;
} t[MARX];
int N, M, NodeNum, Root;
//=============================================================
inline int read()
{
int f = 1, w = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
bool GetSonNum(int now) {return t[Fat].Son[1] == now;}
int NewNode(int Fa, int Val)
{
++ NodeNum;
t[NodeNum].Cnt = t[NodeNum].Size = 1, t[NodeNum].Fa = Fa, t[NodeNum].Val = Val;
if(Val == 0 || Val == N + 1) t[NodeNum].Val = Val ? - INF : INF;
return NodeNum;
}
void Pushup(int now)
{
if(! now) return ;
t[now].Size = t[now].Cnt;
if(ls) t[now].Size += t[ls].Size;
if(rs) t[now].Size += t[rs].Size;
}
void Pushdown(int now)
{
if(! now || ! t[now].tag) return ;
t[t[now].Son[0]].tag ^= 1, t[t[now].Son[1]].tag ^= 1;
std :: swap(t[now].Son[0], t[now].Son[1]);
t[now].tag = 0;
}
void Rotate(int now)
{
int fa = Fat, gfa = t[fa].Fa, WhichSon = GetSonNum(now);
t[fa].Son[WhichSon] = t[now].Son[WhichSon ^ 1];
t[t[fa].Son[WhichSon]].Fa = fa;
t[now].Son[WhichSon ^ 1] = fa; t[fa].Fa = now;
t[now].Fa = gfa;
if(gfa) t[gfa].Son[t[gfa].Son[1] == fa] = now;
Pushup(fa), Pushup(now);
}
void Splay(int now, int Target)
{
for(int fa = Fat; (fa = Fat) != Target; Rotate(now))
if(t[fa].Fa != Target) Rotate(GetSonNum(now) == GetSonNum(fa) ? fa : now);
if(! Target) Root = now;
}
int Kth(int now, int Size)
{
while(1)
{
Pushdown(now);
if(Size <= t[t[now].Son[0]].Size) {now = t[now].Son[0]; continue;}
if(Size == t[t[now].Son[0]].Size + 1) return now;
Size -= t[t[now].Son[0]].Size + 1, now = t[now].Son[1];
}
}
void Reverse(int L, int R)
{
L = Kth(Root, L),
R = Kth(Root, R);
Splay(L, 0),
Splay(R, L);
t[t[t[Root].Son[1]].Son[0]].tag ^= 1;
}
int Build(int fa, int L, int R)
{
if(L > R) return 0;
int mid = (L + R) >> 1, now = NewNode(fa, mid);
t[now].Son[0] = Build(now, L, mid - 1);
t[now].Son[1] = Build(now, mid + 1, R);
Pushup(now);
return now;
}
void Print(int now)
{
if(! now) return ;
Pushdown(now);
Print(t[now].Son[0]);
if(t[now].Val >= 1 && t[now].Val <= N) printf("%d ", t[now].Val);
Print(t[now].Son[1]);
}
//=============================================================
int main()
{
N = read(), M = read();
Root = Build(0, 0, N + 1);
for(int i = 1; i <= M; i ++)
{
int L = read(), R = read();
Reverse(L, R + 2);
}
Print(Root);
return 0;
}
Fhq-Treap
/*
By:Luckyblock
FHQ-treap
*/
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <ctype.h>
#define min std::min
#define max std::max
#define ll long long
const int MARX = 1e5 + 10;
//=============================================================
struct FhqTreapNode
{
int son[2], val, Rand, size;
bool tag;
} t[MARX];
int N, M, NodeNum, Root;
//=============================================================
inline int read()
{
int f = 1, w = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
for(; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void Update(int x)
{
t[x].size = t[t[x].son[0]].size + t[t[x].son[1]].size + 1;
if(! x || ! t[x].tag) return ;
t[x].tag ^= 1;
std :: swap(t[x].son[0], t[x].son[1]);
t[t[x].son[0]].tag ^= 1, t[t[x].son[1]].tag ^= 1;
}
int NewNode(int Val)
{
NodeNum ++;
t[NodeNum] = (FhqTreapNode) {0, 0, Val, rand(), 1, 0};
// t[NodeNum].size = 1; t[NodeNum].val = Val; t[NodeNum].Rand = rand();
return NodeNum;
}
int Build(int L, int R)
{
if(L > R) return 0;
int mid = (L + R) >> 1, Val = mid - 1;
int now = NewNode(Val);
t[now].son[0] = Build(L, mid - 1);
t[now].son[1] = Build(mid + 1, R);
Update(now);
return now;
}
int Merge(int x, int y)
{
if(! x || ! y) return x + y;
Update(x), Update(y);
if(t[x].Rand < t[y].Rand)
{
t[x].son[1] = Merge(t[x].son[1], y);
Update(x);
return x;
}
t[y].son[0] = Merge(x, t[y].son[0]);
Update(y);
return y;
}
void Split(int now, int Key, int &x, int &y)
{
if(! now) {x = y = 0; return ;}
Update(now);
if(Key <= t[t[now].son[0]].size) y = now, Split(t[now].son[0], Key, x, t[y].son[0]);
else x = now, Split(t[now].son[1], Key - t[t[now].son[0]].size - 1, t[x].son[1], y);
Update(now);
}
void Reverse(int L, int R)
{
int tmp1, tmp2, tmp3, tmp4;
Split(Root, R + 1, tmp1, tmp2), Split(tmp1, L, tmp3, tmp4);
t[tmp4].tag ^= 1; Root = Merge(Merge(tmp3, tmp4), tmp2);
}
void Print(int x)
{
if(! x) return ;
Update(x);
Print(t[x].son[0]);
if(t[x].val >= 1 && t[x].val <= N) printf("%d ", t[x].val);
Print(t[x].son[1]);
}
//=============================================================
int main()
{
srand(time(0));
N = read(), M = read();
Root = Build(1, N + 2);
for(int i = 1, L, R; i <= M; i ++) L = read(), R = read(), Reverse(L, R);
Print(Root);
return 0;
}
作者@Luckyblock,转载请声明出处。