01-trie练习

这里用递归实现01-trie, 可以看做是区间长度为2的幂的权值线段树, 能实现权值的所有操作, 异或时, 翻转左右儿子即可.

 

练习1 CF 817E Choosing The Commander

 

大意: 要求维护一个集合, 给定三种操作:

1. 插入属性$p_i$的元素

2. 删除属性$p_i$的元素

3. 询问集合中有多少元素异或$p_i$后的值小于$l_i$

 

算是比较简单的01-trie入门题, 假若每次都异或0的话, 完全就是裸的权值, 非0的话, 对于非0位翻转左右儿子即可

#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstdio>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;

const int N = 1e5+10, sz = 27;
int n, T, tot;
struct {int ch[2],sum;} tr[N<<5];


void add(int &o, int d, int x, int v) {
	if (!o) o=++tot;
	tr[o].sum += v;
	if (d>=0) add(tr[o].ch[x>>d&1],d-1,x,v);
}

int query(int o, int d, int x, int v) {
	if (!o) return 0;
	int f1 = x>>d&1, f2 = v>>d&1;
	if (f2) return tr[tr[o].ch[f1]].sum+query(tr[o].ch[f1^1],d-1,x,v);
	return query(tr[o].ch[f1],d-1,x,v);
}


int main() {
	scanf("%d", &n);
	REP(i,1,n) {
		int op, x, v;
		scanf("%d%d", &op, &x);
		if (op==1) add(T,sz,x,1);
		else if (op==2) add(T,sz,x,-1);
		else {
			scanf("%d", &v);
			printf("%d\n", query(T,sz,x,v));
		}
	}
}

 

 

 

练习2 : CF 842D Vitya and Strange Lesson

大意: 给定$n$个数的集合, 每次将集合中所有数异或$x$, 求整个集合的mex

#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstdio>
#define REP(i,a,n) for(int i=a;i<=n;++i)
using namespace std;

const int N = 1<<19;
int n, m, tot, T;
int vis[N];
struct {int ch[2],sum;} tr[N<<2];

void ins(int &o, int d, int x) {
    if (!o) o=++tot;
    ++tr[o].sum;
    if (d>=0) ins(tr[o].ch[x>>d&1],d-1,x);
}

int query(int o, int d, int x) {
    if (d<0) return 0;
    int t = x>>d&1;
    if (tr[tr[o].ch[t]].sum==(1<<d)) return (1<<d)^query(tr[o].ch[t^1],d-1,x);
    return query(tr[o].ch[t],d-1,x);
}


int main() {
    scanf("%d%d", &n, &m);
    REP(i,1,n) { 
        int t;
        scanf("%d", &t);
        if (vis[t]) continue;
        vis[t] = 1;
        ins(T,18,t);
    }
    int num = 0;
    REP(i,1,m) {
        int t;
        scanf("%d", &t);
        printf("%d\n", query(T,18,num^=t));
    }
}

  

 

转载于:https://www.cnblogs.com/uid001/p/10256496.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值