2023河南萌新联赛第(二)场:河南工业大学 B题 Trie树维护异或值

 

这道题还是很值得整理的,每次插入一个数或者删除一个数,每次给你两个数字x,h 问你给定的插入的集合中的 a 与x异或值大于等于h的到底有几个?

想到用trie树之后我们记得之前做过一个一堆数中选择两个数字让他们的异或值最大,是贪心的做

每插入一个数字我们就查询当前已经插入的数字和它异或值最大的结果(每次在走路径的时候优先走二进制位反着的就行了)

这个题问我们的 发现可以标记已经走过的路径,然后删除一个数的话也就是删除路径上的标记

查询的话,我们需要这样做,我们从高位往低位来做,首先h的二进制位数为0的时候我们要加上可以走到1的数目,然后顺着它的路径继续向前走,因为我们求的是严格大于它的数字,我们走的时候是1的话就想办法顺着它走就可以了,还是很有教育意义的一个题目

// Problem: 异星突击
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/61657/B
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define int long long
#define ls u<<1
#define rs u<<1|1
#define inf LLONG_MIN
#define _inf LLONG_MAX
#define fs first
#define se second
#define pb push_back

using namespace std;
const int N = 1e5*32;
int T;
int tr[N][3],idx;
int cnt[N];
void insert(int x,int c){
	int p =0;
	for(int i=31;~i;i--){
		int j = x>>i&1;
		if(!tr[p][j]) tr[p][j] = ++idx;
		p = tr[p][j];
		cnt[p]+=c;
	}
}


int query(int x,int h){
	int p =0;
	int res = 0;
	for(int i=31;~i;i--){
		int j = x>>i&1;
		if(h>>i&1) p = tr[p][!j];
		else{
	      res+=cnt[tr[p][!j]];
	      p = tr[p][j];		
		}
		
		if(!p)return res;
	}
	
	return res;
}

void solve()
{
	int n,hp;
	cin>>n>>hp;
	while(n--){
		int id,x,h;
		cin>>id>>x;
		if(id==0){
			insert(x,1);
		}else if(id==1){
			insert(x,-1);
		}else{
			cin>>h;
			int num = query(x,h);
			cout<<num<<"\n";
			if(!num)
			 hp--;
			
		}
	}
	cout<<hp<<"\n";
	
	
}



signed main()
{
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	//cin>>T;
	T = 1;
	while(T--)solve();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值