题目链接:点我啊╭(╯^╰)╮
F ( l , r ) = A l & A l + 1 & . . . & A r F(l, r) = A_l \& A_{l+1} \& ... \& A_{r} F(l,r)=Al&Al+1&...&Ar
S ( l , r ) = { F ( a , b ) ∣ m i n ( l , r ) ≤ a ≤ m a x ( l , r ) } S(l, r) = \{F(a, b) | min(l, r) ≤ a ≤ max(l, r)\} S(l,r)={F(a,b)∣min(l,r)≤a≤max(l,r)}
Q Q Q 次查询 l l l 和 r r r,求 S ( l , r ) S(l, r) S(l,r)
一个数字连续作与操作,不同数字最多出现 l o g log log 个
因此对每个 a i a_i ai,记录它往左不停作与操作出现的不同数字
这里我们要查询 S ( l , r ) S(l, r) S(l,r),也就是以 r r r 为右端点,做与操作的不同数字且产生过程都在 l l l 右端
联想到主席树求区间不同数字的操作
这里就可以在记录 a i a_i ai 往左不停作与操作出现的不同数字 的同时
维护产生这些数字的左端点的最大值
这个最大值 m a x max max 就是我们查询 S ( l , r ) S(l, r) S(l,r) 时, l l l 必须要 ≤ m a x ≤max ≤max
因为所有的不同数字最多 n l o g n nlogn nlogn 个,因此直接用 m a p map map 维护最大值即可
时间复杂度: O ( n l o g 2 n + q l o g n ) O(nlog^2n +qlogn) O(nlog2n+qlogn)
#include
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair pii;
const int maxn = 1e5 + 5;
int T, n, q, lans, tot, root[maxn];
int t[maxn*300], ls[maxn*300], rs[maxn*300];
map mp, tmp, las;
void update(int &rt, int pre, int pos, int c, int l, int r) {
if(l>pos || r> 1;
update(ls[rt], ls[pre], pos, c, l, mid);
update(rs[rt], rs[pre], pos, c, mid+1, r);
}
int query(int rt, int L, int R, int l, int r) {
if(l>R || r=L && r<=R) return t[rt];
int mid = l + r >> 1, ret = 0;
ret += query(ls[rt], L, R, l, mid);
ret += query(rs[rt], L, R, mid+1, r);
return ret;
}
signed main() {
scanf("%d", &n);
for(int i=1, x; i<=n; ++i) {
scanf("%d", &x);
root[i] = root[i-1];
mp[x] = i; tmp.clear();
for(auto j : mp) {
int fi = j.first, se = j.second;
tmp[fi & x] = max(tmp[fi & x], se);
}
for(auto j : tmp) {
int fi = j.first, se = j.second;
if(las[fi] == se) continue;
update(root[i], root[i], las[fi], -1, 1, n);
las[fi] = se;
update(root[i], root[i], las[fi], 1, 1, n);
}
mp.swap(tmp);
}
scanf("%d", &q);
while(q--) {
int l, r;
scanf("%d%d", &l, &r);
l = (l ^ lans) % n + 1;
r = (r ^ lans) % n + 1;
if(l > r) swap(l, r);
printf("%d\n", lans = query(root[r], l, r, 1, n));
}
}