给出\(n\)个数的序列,每个位置都有一个权值\(c\),进行 \(Q\) 次询问,每次询问给定一个区间 \([l,r]\) 和两个数字 \(a,b\),问这个序列有多少种权值 \(c\)满足 \(c ^ a <= b\)。
莫队+分块
莫队参考 : 莫队详解 - JSOI爆零珂学家yzhang - 博客园 (cnblogs.com)
仅考虑第 \(j\)位,
\(b\)为1,\(a\)为1,那么 \(c\)为1可满足 \(c ^ a < b\)
\(b\)为1,\(a\)为1,那么 \(c\)为0可满足 \(c ^ a < b\)
\(b\)为0,\(a\)为1,那么 \(c\)只能为1才可满足 \(c ^ a <= b\)
\(b\)为0,\(a\)为0,那么 \(c\)只能为0才可满足 \(c ^ a <= b\)
所以对于前两种情况,我们直接暴力计算其对答案的贡献即可。
即:从高位往低位遍历,当第 \(j\)位出现前两种情况时,直接利用分块+前缀和 计算出当前数对答案的贡献即可。
#include <bits/stdc++.h> #define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0) #define fi first #define se second #define PII pair<int, int> #define pb push_back using namespace std; const int N = 2e5 + 7; const int inf = 0x3f3f3f3f; inline int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();} while (isdigit(ch)){x=x*10+ch-48;ch=getchar();} return x*f; } struct query{ int l,r,id,bl; int a,b; }q[N]; int sum[N]; //记录每个分块有多少种c int ans[N]; int cnt[N]; //记录c有多少个 int c[2*N]; //c[i] 表示每个i这个数的种数 int v[N]; int k; //记录分块大小 void add(int x) { if(++cnt[x] == 1) { sum[x / k] ++; c[x] ++; } } void del(int x) { if(--cnt[x] == 0) { sum[x / k] --; c[x] --; } } bool cmp(query a,query b) { if(a.bl != b.bl)return a.bl < b.bl; else return a.r < b.r; } int ask(int x){ //计算前缀和,即到第x位 int res = 0; for (int i = x / k * k; i <= x; i++)res += c[i]; for (int i = 0; i < x / k; i++)res += sum[i]; return res; } void solve(){ int n,m; cin >> n; k = sqrt(n+1); for(int i = 1; i <= n; ++i) cin >> v[i]; cin >> m; for(int i = 1; i <= m; ++i){ cin >> q[i].l >> q[i].r >> q[i].a >> q[i].b; q[i].bl = (q[i].l - 1) / k + 1; q[i].id = i; } sort(q+1,q+1+m,cmp); int l = 1, r = 0; for(int i = 1; i <= m; ++i){ int ll = q[i].l, rr = q[i].r; while(l < ll) del(v[l++]); while(l > ll) add(v[--l]); while(r < rr) add(v[++r]); while(r > rr) del(v[r--]); int s = 0; int a = q[i].a, b = q[i].b; for(int j = 19; j > -1; --j){ if((b >> j) & 1){ int p = s; if((a >> j) & 1) p |= 1 << j; else s |= 1 << j; ans[q[i].id] += ask(p + (1 << j) - 1) - ask(p - 1); } else if((a >> j) & 1)s |= 1 << j; } ans[q[i].id] += c[q[i].a ^ q[i].b]; } for(int i = 1; i <= m; i++) cout << ans[i] << "\n"; } int main() { #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif qc; int T; //cin >> T; T = 1; while(T--){ solve(); } return 0; }