普通平衡树
/*
无旋treap(fhq treap)
treap是二叉搜索树结合二叉堆来的,
它保证树上任意节点,右节点值一定大于当前节点,儿子节点的索引一定小于父亲节点
对于任意一个点随机赋索引,这样的树就保证了随机,从而不会被卡链
无旋treap主要引入了分裂和合并两个操作,从而可用来处理很多问题
*/
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
const int maxn = 1e5+5;
struct node{
int l,r; //左右子树
int val,key; //节点值和一个随机索引
int siz; //子树大小
}fhq[maxn];
int cnt,root;
int newnode(int val) //新建一个节点
{
fhq[++cnt].val = val;
fhq[cnt].key = rand();
fhq[cnt].siz = 1;
return cnt;
}
void update(int x)
{
fhq[x].siz = fhq[fhq[x].l].siz + fhq[fhq[x].r].siz + 1;
}
void split(int now,int val,int &x,int &y) //将树按值分裂,分裂为一棵值都小于等于val和值都大于val的,根分别为x和y
{
if( !now )
{
x = y = 0;
return;
}
if( fhq[now].val <= val )
{
x = now; //这个节点及其子树都属于第一棵树
split(fhq[now].r,val,fhq[now].r,y);
//右子树中还需要相同的分解,因为里面的值可能大于val也可能小于它。
//这里传的是引用,所以右子树在之后的递归被确定时就连上去了
}else
{
y = now;
split(fhq[now].l,val,x,fhq[now].l);
}
update(now); //最后更新一下当前节点
}
int merge(int x,int y) //将x与y这两棵树合并,返回合并后树的根节点,必须保证x里面所有的值都小于y里的值
{
if( !x || !y ) return x+y;
if( fhq[x].key > fhq[y].key ) //x的索引大于y,说明x必须在y的上方
{
fhq[x].r = merge(fhq[x].r,y); //y的值又大于x的所有值,所以y一定在x的右子树上,合并x的右子树和y即可
update(x); //记得更新siz
return x;
}else
{
fhq[y].l = merge(x,fhq[y].l);
update(y);
return y;
}
}
int x,y,z;
void ins(int val) //插入一个值为val的节点
//将原树按val分裂成两棵树x,y,再合并x与新节点,最后合并y
{
split(root,val,x,y);
root = merge(merge(x,newnode(val)),y);
}
void del(int val) //删除一个值为val的节点
//将原树按val分裂成x、z,再把x按val-1分裂成x、y.然后删去y的根节点,即合并y的左子树和右子树,再合并剩下的三棵树
{
split(root,val,x,z);
split(x,val-1,x,y);
y = merge(fhq[y].l,fhq[y].r);
root = merge(merge(x,y),z);
}
int rank(int val) //查询val值的排名
//将原树按val-1分裂,答案就是x树的大小,记得合并回去
{
split(root,val-1,x,y);
int ans = fhq[x].siz+1;
root = merge(x,y);
return ans;
}
int atrank(int x) //查询第x大
{
int now = root;
while( 1 )
{
if( x == fhq[fhq[now].l].siz + 1 ) return fhq[now].val;
if( fhq[fhq[now].l].siz >= x ) now = fhq[now].l; //在左子树
else //在右子树
{
x -= fhq[fhq[now].l].siz + 1;
now = fhq[now].r;
}
}
}
int pre(int val) //查询val值的前驱
//将原树按val-1分裂,答案就是x树上的最大值
{
split(root,val-1,x,y);
int p = x;
while( fhq[p].r ) p = fhq[p].r;
root = merge(x,y); //记得合并回去
return fhq[p].val;
}
int nxt(int val) //查询val值的后继
//将原树按val分裂,答案就是y树上的最小值
{
split(root,val,x,y);
int p = y;
while( fhq[p].l ) p = fhq[p].l;
root = merge(x,y);
return fhq[p].val;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
srand(time(NULL));
int q;
cin >> q;
while( q-- )
{
int op,x;
cin >> op >> x;
if( op == 1 ) ins(x);
else if( op == 2) del(x);
else if( op == 3 ) cout << rank(x) << '\n';
else if( op == 4 ) cout << atrank(x) << '\n';
else if( op == 5 ) cout << pre(x) << '\n';
else cout << nxt(x) << '\n';
}
return 0;
}
文艺平衡树
/*
无旋treap实现文艺平衡树
平衡树上维护的是按下标排序的树
翻转[l,r]区间时,将树分裂成[1,l-1]、[l,r]、[r+1,n]这三棵,对中间那棵打上懒标记即可
所以这里用的是按大小分裂
*/
#include <iostream>
#include <cstdlib>
#include <vector>
#include <ctime>
using namespace std;
const int maxn = 1e5+5;
struct node{
int l,r; //左右子树
int id,key; //节点值和一个随机索引
int siz,lazy; //子树大小
}fhq[maxn];
int cnt,root;
int newnode(int id) //新建一个节点
{
fhq[++cnt].id = id;
fhq[cnt].key = rand();
fhq[cnt].siz = 1;
return cnt;
}
void update(int x)
{
fhq[x].siz = fhq[fhq[x].l].siz + fhq[fhq[x].r].siz + 1;
}
void pushdown(int x)
{
if( fhq[x].lazy )
{
swap(fhq[x].l,fhq[x].r);
fhq[x].lazy = 0,fhq[fhq[x].l].lazy ^= 1,fhq[fhq[x].r].lazy ^= 1;
}
}
void split(int now,int size,int &x,int &y) //将树按size分裂,分裂为一棵siz等于size和剩下的一棵树,根分别为x和y
{
if( !now )
{
x = y = 0;
return;
}
pushdown(now);
if( fhq[fhq[now].l].siz < size )
{
x = now; //这个节点及其子树都属于第一棵树
split(fhq[now].r,size-fhq[fhq[now].l].siz-1,fhq[now].r,y); //记得把size减一下
}else
{
y = now;
split(fhq[now].l,size,x,fhq[now].l);
}
update(now); //最后更新一下当前节点
}
int merge(int x,int y)
{
if( !x || !y ) return x+y;
if( fhq[x].key > fhq[y].key )
{
pushdown(x); //记得下传标记
fhq[x].r = merge(fhq[x].r,y);
update(x);
return x;
}else
{
pushdown(y);
fhq[y].l = merge(x,fhq[y].l);
update(y);
return y;
}
}
int x,y,z;
void ins(int id) //插入一个编号为id的节点
//将原树按id-1大小分裂成两棵树x,y,再合并x与新节点,最后合并y
{
split(root,id-1,x,y);
root = merge(merge(x,newnode(id)),y);
}
void reverse(int l,int r) //翻转一个区间
{
split(root,l-1,x,y); //拆成l-1和剩下的
split(y,r-l+1,y,z); //将剩下拆成r-l+1和剩下的,那么y整棵树就是要操作的区间
fhq[y].lazy ^= 1; //打上标记即可
root = merge(merge(x,y),z);
}
vector<int> ans;
void dfs(int x)
{
if( !x ) return;
pushdown(x);
dfs(fhq[x].l);
ans.push_back(fhq[x].id);
dfs(fhq[x].r);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
srand(time(NULL));
int n,q;
cin >> n >> q;
for (int i = 1; i <= n; i++) ins(i); //记住这里是编号
while( q-- )
{
int l,r;
cin >> l >> r;
reverse(l,r);
}
dfs(root);
for (int i = 0; i < ans.size(); i++)
{
cout << ans[i];
if( i == ans.size() - 1 ) cout << '\n';
else cout << ' ';
}
return 0;
}