1 条题解
-
0
注意到 是从最低位开始的,所以我们把数字按照二进制位从低位往高位插进字典树。
插入和删除操作是平凡的。查最大 只需要从根节点开始走,能走使这一位异或为 的边就走这一条边,否则直接返回,因为不可能有更大的 值。
接下来考虑处理操作 。满足要求的数字部分是容易提取的,在字典树上走使这一位异或为 的边,直到第 位。这一位对应的子树中存储的数值肯定满足要求。
然后考虑如何整体增加。我们发现对于如果字典树中的数据整体加 ,最低位为 的数只有最低位会变化,最低位变成 。而最低位为 的数最低位变成 ,且之后高一位会增加 。这相当于交换左右根节点儿子,并递归处理交换后的左儿子。这启发我们使用懒标记处理这个问题,上述的就是增加过程。
然而对于子树增加,这么做是困难的。因此,我们把这棵满足要求的子树和这棵子树的根到整个树的根分裂出来,打上懒标记,然后再合并回去。这么做的时间复杂度可以类比线段树合并与分裂的时间复杂度,为整体 。
最后考虑整体加 。我们沿用上面的思路,对于这一位加 其实可以转化为对于下一位加 。并且如果 为奇数,就还需要在这一位处理一下加 ,因为这一个加 没有下推。
#include <bits/stdc++.h> using namespace std; long long q,op,k,v,x,trie[10000000][2],tol[10000000],ad[10000000],cnt=1; void pushdown(long long x) { if(ad[x]&1)swap(trie[x][0],trie[x][1]),ad[trie[x][0]]++; ad[trie[x][0]]+=(ad[x]>>1),ad[trie[x][1]]+=(ad[x]>>1),ad[x]=0; } void insert(long long x) { long long rt=1; tol[rt]++; for(long long i=0;i<=32;i++) { pushdown(rt); long long id=(x>>i)&1; if(!trie[rt][id])trie[rt][id]=++cnt; rt=trie[rt][id],tol[rt]++; } } void del(long long x) { long long rt=1; tol[rt]--; for(long long i=0;i<=32;i++) { pushdown(rt); long long id=(x>>i)&1; rt=trie[rt][id],tol[rt]--; } } long long merge(long long x,long long y) { if(!x||!y)return x+y; pushdown(x),pushdown(y); tol[x]+=tol[y],trie[x][0]=merge(trie[x][0],trie[y][0]),trie[x][1]=merge(trie[x][1],trie[y][1]); return x; } void update(long long x,long long k,long long v) { long long rt=1,pt=++cnt,now=pt,pr=0,prt=0,pd=0,tmp=0; if(k==0) { pushdown(rt),ad[rt]+=v; return; } for(long long i=0;i<k;i++) { pushdown(rt); long long id=(x>>i)&1; if(!trie[rt][id]||!tol[trie[rt][id]])return; pr=rt,pd=id,prt=pt; trie[pt][id]=++cnt,rt=trie[rt][id],pt=trie[pt][id]; } pushdown(rt); trie[pr][pd]=0,trie[prt][pd]=rt,tmp=tol[rt]; rt=1,pt=now; for(long long i=0;i<k;i++) { pushdown(rt); long long id=(x>>i)&1; tol[rt]-=tmp,tol[pt]=tmp; rt=trie[rt][id],pt=trie[pt][id]; } ad[now]+=v,merge(1,now); } long long getmax(long long x) { long long rt=1,mx=0; for(long long i=0;i<=32;i++) { pushdown(rt); long long id=(x>>i)&1; if(!trie[rt][id]||!tol[trie[rt][id]])return mx; mx=max(mx,i+1),rt=trie[rt][id]; } return 32; } int main() { scanf("%d",&q); for(long long i=1;i<=q;i++) { scanf("%lld",&op); if(op==1)scanf("%lld",&x),insert(x); else if(op==2)scanf("%lld",&x),del(x); else if(op==3)scanf("%lld%lld%lld",&x,&k,&v),update(x,k,v); else if(op==4)scanf("%lld",&x),printf("%lld\n",(1ll<<getmax(x))); } return 0; }
- 1
信息
- ID
- 79
- 时间
- 3000ms
- 内存
- 512MiB
- 难度
- 8
- 标签
- 递交数
- 215
- 已通过
- 34
- 上传者