标签:size for ++ 递归 mes 个数 and struct 异或操作
一般习惯用递归实现01-trie, 可以看做是区间长度为2的幂的权值线段树, 能实现权值线段树的所有操作, 同时还可以实现一些异或操作
const int N = 1<<20; struct {int ch[2],sum;} tr[N<<1]; 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); }
这里用结构体存储$trie$树, $d$表示当前深度, $x$为插入元素, 叶结点深度为$-1$
假设元素范围均在$[0,1<<20)$, 若插入一个数$x$可以写成 $ins(T,19,x)$
空间占用是$O(N)$的, 由于是动态开点, $tr$数组只需开到$2N$即可
若元素范围过大, 空间占用是$O(mlogN)$, 一般要开到$40m$, $m$是操作次数
练习1 : 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)); } }
练习2
标签:size for ++ 递归 mes 个数 and struct 异或操作
原文地址:https://www.cnblogs.com/uid001/p/10256496.html