FHQ-Treap
全码
优点:码量短
写错了的话,\(TLE,MLE,Wa\)全家桶
包含合并操作
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
#define pii pair<int,int>
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int N = 1e6+5;
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
int rand()
{
uniform_int_distribution<ll>rg(LONG_LONG_MIN,LONG_LONG_MAX);
return rg(rnd)%INT_MAX;
}
struct FHQ_Treap
{
int ch[N][2],sz[N],rt,tot,id[N],v[N];
inline void pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
inline int newnode(int x)
{
sz[++tot]=1;v[tot]=x;id[tot]=rand();
return tot;
}
inline int merge(int x,int y)
{
if(!x||!y)return x^y;
if(id[x]<id[y])return ch[x][1]=merge(ch[x][1],y),pushup(x),x;
return ch[y][0]=merge(x,ch[y][0]),pushup(y),y;
}
inline void split(int now,int k,int &x,int &y)
{
if(!now)x=0,y=0;
else
{
if(k>=v[now])x=now,split(ch[now][1],k,ch[now][1],y);
else y=now,split(ch[now][0],k,x,ch[now][0]);
pushup(now);
}
}
inline void insert(int k)
{
int x,y;
split(rt,k,x,y);
rt=merge(merge(x,newnode(k)),y);
}
inline void del(int k)
{
int x,y,z;
split(rt,k,x,y);
split(x,k-1,x,z);//attention is x not rt
z=merge(ch[z][0],ch[z][1]);rt=merge(merge(x,z),y);
}
inline int kth(int now,int k)
{
while(1)
{
if(k<=sz[ch[now][0]])now=ch[now][0];
else if(k==sz[ch[now][0]]+1)return now;
else k-=sz[ch[now][0]]+1,now=ch[now][1];
}
}
inline int rank(int k)
{
int x,y;
split(rt,k-1,x,y);int ans=sz[x]+1;
return rt=merge(x,y),ans;
}
inline int pre(int k)
{
int x,y,ans;
split(rt,k-1,x,y);
ans=v[kth(x,sz[x])];
return rt=merge(x,y),ans;
}
inline int nxt(int k)
{
int x,y,ans;
split(rt,k,x,y);
ans=v[kth(y,1)];
return rt=merge(x,y),ans;
}
}tree;
int n;
int main()
{
speed();
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
cin>>n;
int opt,x;
for(int i=1;i<=n;i++)
{
cin>>opt>>x;
if(opt==1)
{
tree.insert(x);
}else if(opt==2)
{
tree.del(x);
}else if(opt==3)
{
cout<<tree.rank(x)<<endl;
}else if(opt==4)
{
cout<<tree.v[tree.kth(tree.rt,x)]<<endl;
}else if(opt==5)
{
cout<<tree.pre(x)<<endl;
}else
{
cout<<tree.nxt(x)<<endl;
}
}
return 0;
}
核心函数是合并和分离,所以都是基于\(rand\)维护
合并
格外要注意的是合并\(x\)和\(y\)要保证\(x\)中的所有元素都小于\(y\)中的,这里采用\(id\)小的在上面
int merge(int x,int y)
{
if(!x||!y)return x^y;//返回非0项
if(id[x]<id[y])return ch[x][1]=merge(ch[x][1],y),up(x),x;
return ch[y][0]=merge(x,ch[y][0]),up(y),y;
}
分裂操作,递归分裂,注意细节
注意\(x\)包含\(k\),\(y\)不包含\(k\)
inline void split(int now,int k,int &x,int &y)
{
if(!now)x=0,y=0;
else
{
if(k>=v[now])x=now,split(ch[now][1],k,ch[now][1],y);//一定要记得更新x,y
else y=now,split(ch[now][0],k,x,ch[now][0]);//一定要记得更新x,y
pushup(now);
}
}
插入,删除
inline void insert(int k)
{
int x,y;
split(rt,k,x,y);
rt=merge(merge(x,newnode(k)),y);
}
inline void del(int k)
{
int x,y,z;
split(rt,k,x,y);
split(x,k-1,x,z);//attention is x not rt
z=merge(ch[z][0],ch[z][1]);rt=merge(merge(x,z),y);
}
查询第\(k\)小
inline int kth(int now,int k)
{
while(1)
{
if(k<=sz[ch[now][0]])now=ch[now][0];
else if(k==sz[ch[now][0]]+1)return now;
else k-=sz[ch[now][0]]+1,now=ch[now][1];
}
}
查询权值的排名
inline int rank(int k)
{
int x,y;
split(rt,k-1,x,y);int ans=sz[x]+1;
return rt=merge(x,y),ans;
}
查询前驱,后继
inline int pre(int k)
{
int x,y,ans;
split(rt,k-1,x,y);
ans=v[kth(x,sz[x])];
return rt=merge(x,y),ans;
}
inline int nxt(int k)
{
int x,y,ans;
split(rt,k,x,y);
ans=v[kth(y,1)];
return rt=merge(x,y),ans;
}
文艺平衡树
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
#define pii pair<int,int>
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int N = 1e6+5;
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
int rand()
{
uniform_int_distribution<ll>rg(LONG_LONG_MIN,LONG_LONG_MAX);
return rg(rnd)%INT_MAX;
}
struct FHQ_Treap
{
int ch[N][2],tag[N],sz[N],v[N],id[N],tot,rt;
void pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
inline void lazytag(int x)
{
swap(ch[x][0],ch[x][1]);
tag[ch[x][0]]^=1;tag[ch[x][1]]^=1;
}
inline void pushdown(int x)
{
if(!tag[x])return;
swap(ch[x][0],ch[x][1]);
lazytag(ch[x][0]);lazytag(ch[x][1]);tag[x]=0;
}
inline int newnode(int x)
{
tag[++tot]=0;id[tot]=rand();sz[tot]=1;
v[tot]=x;return tot;
}
inline void split(int now,int k,int &x,int &y)
{
if(!now)x=0,y=0;
else
{
pushdown(now);
if(k>sz[ch[now][0]])x=now,split(ch[now][1],k-sz[ch[now][0]]-1,ch[now][1],y);
else y=now,split(ch[now][0],k,x,ch[now][0]);
pushup(now);
}
}
inline int merge(int x,int y)
{
if(!x||!y)return x^y;
if(id[x]<id[y])return pushdown(x),ch[x][1]=merge(ch[x][1],y),pushup(x),x;
return pushdown(y),ch[y][0]=merge(x,ch[y][0]),pushup(y),y;
}
inline void insert(int k)
{
int x,y;
split(rt,k,x,y);
rt=merge(merge(x,newnode(k)),y);
}
inline void reverse(int l,int r)
{
int x,y,z;
split(rt,r,x,y);
split(x,l-1,x,z);
lazytag(z);
rt=merge(merge(x,z),y);
}
inline void print(int u)
{
if(!u)return;
pushdown(u);
if(ch[u][0])print(ch[u][0]);
cout<<v[u]<<" ";
if(ch[u][1])print(ch[u][1]);
}
}tree;
int n,m;
int main()
{
speed();
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
cin>>n>>m;int l,r;
for(int i=1;i<=n;i++)tree.insert(i);
while(m--)
{
cin>>l>>r;
tree.reverse(l,r);
}
tree.print(tree.rt);
return 0;
}
关于\(split\)操作,为什么要用\(k\)和\(siz\)比较,因为此时维护的是翻转过的序列,已经不是按照大小关系排的二叉树了,而是按照\(siz\)
区间修改操作
例题
点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
#define pb push_back
#define ull unsigned long long
#define int long long
using namespace std;
#define ts cout<<"****************"<<endl;
const int N =2e5+1000,mod=1e6;
const ull B= 233;
int sz[N],ch[N][2],id[N],tot,rt;
int n;
mt19937 seed(chrono::system_clock::now().time_since_epoch().count());
int Rand()
{
uniform_int_distribution<int>rang(1,INT_MAX);
return rang(seed);
}
inline void write(int x)
{
return x<0?(putchar_unlocked('-'),write(-x),void(0)):(x==0?void(0):(write(x/10),putchar_unlocked((x%10)|48),void(0)));
}
inline int read()
{
int x=0,f=1;char ch=getchar_unlocked();
for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
int a[N],m;char s[N];
int tur[N],add[N],maxn[N];
struct FHQ
{
inline void pushup(int x)
{
sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
maxn[x]=a[x];
if(ch[x][0])
maxn[x]=max(maxn[x],maxn[ch[x][0]]);
if(ch[x][1])
maxn[x]=max(maxn[x],maxn[ch[x][1]]);
// cout<<maxn[x]<<" "<<x<<endl;
}
inline void pushdown(int x)
{
if(tur[x])
{
if(ch[x][0])tur[ch[x][0]]^=1;
if(ch[x][1])tur[ch[x][1]]^=1;
// swap(ch[x][0],ch[x][1]);
ch[x][0]^=ch[x][1]^=ch[x][0]^=ch[x][1];
tur[x]=0;
}
if(add[x])
{
int v=add[x];
if(ch[x][0])
{
add[ch[x][0]]+=v;
maxn[ch[x][0]]+=v;
a[ch[x][0]]+=v;
}
if(ch[x][1])
{
add[ch[x][1]]+=v;
maxn[ch[x][1]]+=v;
a[ch[x][1]]+=v;
}
add[x]=0;
}
}
inline int newnode(int x)
{
// cout<<x<<endl;
a[++tot]=0;maxn[tot]=0;
id[tot]=rand();sz[tot]=1;return tot;
}
inline void split(int now,int k,int &x,int &y)
{
if(!now)x=0,y=0;
else
{
pushdown(now);
if(k>sz[ch[now][0]])x=now,split(ch[now][1],k-sz[ch[now][0]]-1,ch[x][1],y);
else y=now,split(ch[now][0],k,x,ch[y][0]);
pushup(now);
}
}
inline int merge(int x,int y)
{
if(x)pushdown(x);
if(y)pushdown(y);
if(!x||!y)return x^y;
if(id[x]<id[y])return ch[x][1]=merge(ch[x][1],y),pushup(x),x;
return ch[y][0]=merge(x,ch[y][0]),pushup(y),y;
}
inline void insert(int k)
{
int x,y;
split(rt,k,x,y);
// cout<<pos<<" "<<y<<endl;
rt=merge(merge(x,newnode(k)),y);
}
inline void del(int k)
{
int x,y,z;
split(rt,k,x,y);
split(x,k-1,x,z);
z=merge(ch[z][0],ch[z][1]);
rt=merge(merge(x,z),y);
}
inline void update1(int l,int r,int val)
{
int x,y,z;
split(rt,r,x,y);
split(x,l-1,x,z);
maxn[z]+=val;
a[z]+=val;
add[z]+=val;
rt=merge(merge(x,z),y);
}
inline void update2(int l,int r)
{
int x,y,z;
split(rt,r,x,y);
split(x,l-1,x,z);
tur[z]^=1;
rt=merge(merge(x,z),y);
}
inline void query(int l,int r)
{
int x,y,z;
split(rt,r,x,y);
split(x,l-1,x,z);
// cout<<z<<" "<<l<<" "<<r<<endl;
maxn[z]?write(maxn[z]):(putchar_unlocked('0'),void(0));
putchar_unlocked('\n');
rt=merge(merge(x,z),y);
}
}tree;
signed main()
{
// freopen("in.in","r",stdin);freopen("ou1.out","w",stdout);
n=read();m=read();
for(int i=1;i<=n;i++)
tree.insert(0);
int com,l,r,val;
while(m--) {
com=read();
if(com==1) {
l=read();r=read();val=read();
tree.update1(l,r,val);
}
if(com==2) {
l=read();r=read();
tree.update2(l,r);
}
if(com==3) {
l=read();r=read();
tree.query(l,r);
}
}
return 0;
}