题目大意:
就是给你
n
n
n个数,
m
m
m次询问
每次询问给你
l
,
r
,
a
,
b
l,r,a,b
l,r,a,b问你在
[
l
,
r
]
[l,r]
[l,r]区间里面有多少
种
种
种数
c
(
X
O
R
)
a
≤
b
c(XOR)a\leq b
c(XOR)a≤b
解题思路:
这里我们对两个东西进行分块,首先是查询区间分块,然后按照块排序就是莫队了,但是值域怎么维护呢?
但是我们是要查询里面种类数哇,那么我们就要对区间里面的数进行去重,排序,那么我们可以为了和莫队进行配合最好就是分块
我们对值域进行分块把 [ 1 , 1 e 5 ] [1,1e5] [1,1e5]的值域分成 1 e 5 \sqrt {1e5} 1e5块,每个块统计里面的数的种类!!
但是如何查询异或满足上面条件数的个数呢?
就是我们假设是在字典树上面查询的对
a
,
b
a,b
a,b进行按位进行观察
如
果
b
的
第
b
i
t
位
是
1
如果b的第bit位是1
如果b的第bit位是1,
- 如果 c 的 b i t 位 和 a 的 b i t 为 不 同 c的bit位和a的bit为不同 c的bit位和a的bit为不同,那么我们还不能更新答案。
- 如果 c 的 b i t 位 和 a 的 b i t 为 相 同 c的bit位和a的bit为相同 c的bit位和a的bit为相同,那么这一位都比b小了,那么后面怎么取都可以直接去去分块整体进行区间查询
- 固定已经确定的高位,继续往低位看
如 果 b 的 第 b i t 位 是 0 如果b的第bit位是0 如果b的第bit位是0
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{
read(first);
read(args...);
}
struct node {
int l, r, id;
int block;
int a, b;
bool operator < (const node & y) const {
if(block ^ y.block) return block < y.block;
else if(block & 1) return r < y.r;
else return r > y.r;
}
}q[maxn];
int blockqu, blockdate = 316, sz = 17;
int arr[maxn];
int sum[maxn], bl[maxn];
int ans[maxn];
inline void Add(int u) {
if(++ sum[u] == 1) bl[u/blockdate] ++;//值域分块统计每个数的种类
}
inline void Sub(int u) {
if(-- sum[u] == 0) bl[u/blockdate] --;
}
inline int slove(int l, int r) {
int blockl = l/blockdate;
int blockr = r/blockdate;
int ans = 0;
if(blockl == blockr) {
for(int i = l; i <= r; ++ i)
ans += (sum[i] > 0);
return ans;
}
for(int i = blockl+1; i <= blockr-1; ++ i)
ans += bl[i];
for(int i = l; i <= (blockl+1)*blockdate-1; i ++)
ans += (sum[i] > 0);
for(int i = blockr*blockdate; i <= r; ++ i)
ans += (sum[i] > 0);
return ans;
}
inline int cal(int a, int b) {
int hightbit = 0;//统计已经确定的高位
int res = (sum[a^b] > 0);//如果一直递归到底sum[a^b]是没有被计算的
for(int i = sz; i >= 0; -- i) {
int bita = (a >> i) & 1;
int bitb = (b >> i) & 1;
if(bitb) {
//按照字典树上面的查询方式,如果沿着一个方向跑那么高位是被确定好的
int segl = hightbit + (bita ? 1 << i:0);
int segr = segl + (1 << i) - 1;
res += slove(segl,segr);
}
if(bita ^ bitb) hightbit |= (1 << i);
}
return res;
}
int main() {
IOS;
int n;
cin >> n;
for(int i = 1; i <= n; ++ i) cin >> arr[i];
int m;
cin >> m;
blockqu = sqrt(m)+1;
for(int i = 1; i <= m; ++ i) {
int l, r, a, b;
cin >> l >> r >> a >> b;
q[i] = {l,r,i,(l-1)/blockqu+1,a,b};
}
sort(q+1,q+1+m);
int l = 1, r = 0;
for(int i = 1; i <= m; ++ i) {
while(q[i].l < l) Add(arr[--l]);
while(q[i].r > r) Add(arr[++r]);
while(q[i].l > l) Sub(arr[l++]);
while(q[i].r < r) Sub(arr[r--]);
ans[q[i].id] = cal(q[i].a,q[i].b);
}
for(int i = 1; i <= m; ++ i)
cout << ans[i] << endl;
return 0;
}