在补NOIonline
先随手做一下这个T2的弱化版。
感觉这个就是T2的trick
(tire)树认知不够,数位思想差啊。
考虑用(tire)树维护数集,然后高位往低位处理(l),如果(l_i)为(1),则和(p_i)相同一侧子树可以全部加入答案,再走和(p_i)不同一侧递归下去,若(l_i)为0,则必须走(p_i)同侧。
CF817E Choosing The Commander
#include<iostream>
#include<cstdio>
#define ll long long
#define N 100005
ll n;
int cnt;
int ch[N * 16][2],s[N * 16];
inline void insert(ll c){
ll u = 0;
for(int i = 30;i >= 0;--i){
if(!ch[u][(c >> i) & 1])
ch[u][(c >> i) & 1] = ++ cnt;
s[u] ++ ;
u = ch[u][(c >> i) & 1];
// std::cout<<u<<" ";
}
s[u] ++ ;
// puts("");
}
inline void del(ll c){
ll u = 0;
for(int i = 30;i >= 0;--i){
s[u] -- ;
u = ch[u][(c >> i) & 1];
}
s[u] -- ;
}
ll pi,li,ans;
inline void solve(ll u,ll dep){
if(dep == 0)
return;
if((li >> (dep - 1)) & 1){
ll x = (pi >> (dep - 1) & 1);
// std::cout<<u<<" "<<1<<" "<<dep - 1<<" "<<x<<" "<<s[ch[u][x]]<<std::endl;
if(ch[u][x])
ans += s[ch[u][x]];
if(ch[u][!x])
solve(ch[u][!x],dep - 1);
}
else{
ll x = (pi >> (dep - 1) & 1);
// std::cout<<u<<" "<<0<<" "<<dep - 1<<" "<<x<<std::endl;
if(ch[u][x])
solve(ch[u][x],dep - 1);
}
}
int main(){
scanf("%lld",&n);
while(n -- ){
ll opt;
scanf("%lld",&opt);
if(opt == 1){
ll p;
scanf("%lld",&p);
insert(p);
}
if(opt == 2){
ll p;
scanf("%lld",&p);
del(p);
}
if(opt == 3){
scanf("%lld%lld",&pi,&li);
ans = 0;
solve(0,31);
std::cout<<ans<<std::endl;
}
}
}
ps:最近代码能力提上了,不过还要注意对拍。
以及我还是没搞懂(tire)要开多大空间,从这题上看,得开到(16n)(n字符串数量)啊。
下回弄懂了,回来补坑。