返回顶部

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;
}
posted @ 2024-08-21 14:03  wlesq  阅读(9)  评论(0编辑  收藏  举报