P7502 「HMOI R1」不知道是啥的垃圾题

一道很有启发性的题目。

考虑到由于是自然数对的比较,所以我们不能直接用 (01 ext{Trie})

但是考虑到我们可以将 ( ext{Trie}) 转换成有 (4) 个出边的,每一个出边表示数对当前位的 (01) 情况。

然后你考虑查询,对于当前位置,存在一种大于的情况,两种等于的情况,一种小于的情况。

考虑到大于的情况我们可以直接计数,等于的情况就需要递归了,但是由于我们每一层都需要递归两次,效率过低,这该怎么办?

考虑到我们大于情况是只需要数量的,我们可以考虑不建儿子,这样的话对于每一个点,我们可以将 (00)(11) 合并,(01)(10) 合并。这样无论是怎样的情况,等于的递归就只需要进入一个节点即可。

然后每一个节点只需要储存一个数在当前位是 (0)(1) 的个数就行了。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,K=63;
int n;
struct Trie{
	int rt,tot;Trie(){rt=tot=1;}
	struct Node{int son[2],size[2];}tr[N*K];
	void insert(long long x,long long y,int z){
		int u=rt;
		for(int i=K;i>=0;--i){
			int tx=((x>>i)&1),ty=((y>>i)&1);
			if(!tr[u].son[tx^ty]) tr[u].son[tx^ty]=++tot;
			u=tr[u].son[tx^ty],tr[u].size[tx]+=z;
		}
	}
	int query(long long x,long long y){
		int u=rt,res=0;
		for(int i=K;i>=0;--i){
			int tx=((x>>i)&1),ty=((y>>i)&1);
			res+=tr[tr[u].son[tx^ty^1]].size[tx^1];
			u=tr[u].son[tx^ty];
		}
		return res;
	}
}t;
signed main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		int opt;long long x,y;
		scanf("%d%lld%lld",&opt,&x,&y);
		if(opt==1) t.insert(x,y,1);
		else if(opt==2) t.insert(x,y,-1);
		else printf("%d
",t.query(x,y));
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Point-King/p/15338853.html