返回顶部

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;
}

\(FHQ\)的值域有交集,如何合并,这时候\(merge\)就不管用了,\(merge\)是要保证\(x\)中的元素都小于\(y\)中的元素,这时候只能可以递归分裂后合并
详见文章

	inline int join(int x,int y)
	{
		if(!x||!y)return x+y;
		if(id[x]>id[y])swap(x,y);
		int l,r;
		split(y,val[x],l,r);
		ch[x][0]=join(ch[x][0],l);ch[x][1]=join(ch[x][1],r);
		pushup(x);
		return x;
	}

疑问,下面两个\(kth\)为什么注释部分不对

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (ch[rt][0])
#define rid (ch[rt][1])
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 2e6+5,INF=1E9,mod=1e9+7;
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;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
int n;
std::vector<int> edge[N];
int fa[N];
inline void dfs(int u)
{
	for(auto to:edge[u])
	{
		if(to==fa[u])continue;
		fa[to]=u;
		dfs(to);
	}
}
ll sum[N],ans[N];
mt19937 rnd (chrono::system_clock::now().time_since_epoch().count());
int lim;
inline int rd()
{
	uniform_int_distribution<int>rg(1,INT_MAX);
	return rg(rnd);
}
#define int long long
int sz[N],ch[N][2],id[N],tot,cnt[N];ll val[N];int rt[N];
struct FHQ
{
	inline void pushup(int rt)
	{
		sz[rt]=sz[lid]+sz[rid]+cnt[rt];
	}	
	inline int newnode(int c,int s)
	{
		val[++tot]=c;cnt[tot]=s;sz[tot]=s;id[tot]=rd();
		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=y=0;
		else
		{
			if(k>=val[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 &rt,int c,int s)
	{
		int x,y;
		split(rt,c,x,y);
		rt=merge(merge(x,newnode(c,s)),y);
	}
	inline int join(int x,int y)
	{
		if(!x||!y)return x+y;
		if(id[x]>id[y])swap(x,y);
		int l,r;
		split(y,val[x],l,r);
		ch[x][0]=join(ch[x][0],l);
		ch[x][1]=join(ch[x][1],r);
		pushup(x);
		return x;
	}
	inline void move(int &x,int &y,int l,int r)
	{
		int a,b,c;
		split(x,l-1,a,b);
		split(b,r,b,c);
		y=b;
		x=merge(a,c);
	}
	inline int count(int &u,int l,int r)
	{
		int x,y,z;
		split(u,l-1,x,y);
		split(y,r,y,z);
		int ans=sz[y];
		u=merge(merge(x,y),z);
		return ans;
	}
   void split_rk(int u,int c,int &x,int &y){
	    if(!u){
	        x = y = 0;
	        return;
	    }
	    if(sz[ch[u][0]]+cnt[u]<=c){
	        x = u;
	        split_rk(ch[u][1],c-sz[ch[u][0]]-cnt[u],ch[x][1],y);
	    }
	    else{
	        y = u;
	        split_rk(ch[u][0],c,x,ch[y][0]);
	    }
    	pushup(u);
    }
    int kth(int &u,int K){
        int x,y;
        split_rk(u,K-1,x,y);
        int p = y;
        while(ch[p][0])
            p = ch[p][0];
        u = merge(x,y);
        return p?val[p]:-1;
    }
	// inline int kth(int rt,int k)
	// {
	// 	if(sz[rt]<k)return -1;
	// 	int now=rt;

	// 	while(1)
	// 	{
	// 		if(sz[ch[now][0]]+cnt[now]<=k&&k>sz[ch[now][0]])return val[now];
	// 		if(k>sz[ch[now][0]]+cnt[now])k-=sz[ch[now][0]]+cnt[now],k=ch[now][1];
	// 		else if(k<=sz[ch[now][0]])
	// 		{
	// 			now=ch[now][0];
	// 		}
	// 	}
	// }
}T;
int m,idx;
signed main(){
	file("a");
    n = read(),m = read();
    for(int k=1;k<=n;k++)
        T.insert(rt[1],k,read());
    int idx = 1;
    int op,p;
    while(m--){
        int op = read(),p = read();
        if(!op){
            int x = read(),y = read();
            T.move(rt[p],rt[++idx],x,y);
        }
        else if(op==1){
            int t = read();
            rt[p] = T.join(rt[p],rt[t]);
        }
        else if(op==2){
            int x = read(),q = read();
            T.insert(rt[p],q,x);
        }
        else if(op==3){
            int x = read(),y = read();
            write(T.count(rt[p],x,y));
            putchar_unlocked('\n');
        }
        else{
            write(T.kth(rt[p],read()));
            putchar_unlocked('\n');
        }
    }
    return 0;
}
posted @ 2024-08-21 14:03  wlesq  阅读(13)  评论(0编辑  收藏  举报