可持久化线段树+二分
注意到如果[l,r]不降,[l,r-1]就肯定也不降,因此如果能对于每一个位置l,找到最远的r满足不降。这样套上主席树问题就搞定了。
会降当且仅当此时异或上的a[i]的最高位恰好把当前的这一位从1变成0。因此记 f[i][j][0/1] 表示从a[1]开始异或到a[i],以j为最高位的时候,j从1变成0(或0变成1)有多少次。这样二分以后每一位都判一下即可。 O(nlog2n) 。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define H 32
using namespace std;
namespace runzhe2000
{
typedef long long ll;
int n, a[N], sum[N], f[N][H][2], pos[N];
struct seg
{
seg *ch[2];
ll sum_v, sum_1, sum_i;
}mem[N*25], *tot, *root[N], *null;
seg *newseg()
{
seg *x = ++tot; *x = *null;
return x;
}
void init()
{
null = tot = mem; *null = (seg){{null,null},0,0,0};
root[0] = newseg();
}
void insert(seg *x, seg *y, int l, int r, int p, int v, int i)
{
if(l == r)
{
*y = *x;
y->sum_v += v;
y->sum_i += i;
y->sum_1 += 1;
return;
}
int mid = (l+r)>>1;
if(p <= mid) {y->ch[0] = newseg(), y->ch[1] = x->ch[1]; insert(x->ch[0], y->ch[0], l, mid, p, v, i);}
else {y->ch[1] = newseg(), y->ch[0] = x->ch[0]; insert(x->ch[1], y->ch[1], mid+1, r, p, v, i);}
y->sum_v = y->ch[0]->sum_v + y->ch[1]->sum_v;
y->sum_i = y->ch[0]->sum_i + y->ch[1]->sum_i;
y->sum_1 = y->ch[0]->sum_1 + y->ch[1]->sum_1;
}
ll query_v(seg *x, seg *y, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return y->sum_v - x->sum_v; int mid = (l+r)>>1; ll ret = 0;
if(ql <= mid) ret += query_v(x->ch[0], y->ch[0], l, mid, ql, qr);
if(mid < qr) ret += query_v(x->ch[1], y->ch[1], mid+1, r, ql, qr);
return ret;
}
void query_i1(seg *x, seg *y, int l, int r, int ql, int qr, ll &sum_i, ll &sum_1)
{
if(ql <= l && r <= qr) {sum_i += y->sum_i-x->sum_i, sum_1 += y->sum_1-x->sum_1; return;} int mid = (l+r)>>1;
if(ql <= mid) query_i1(x->ch[0], y->ch[0], l, mid, ql, qr, sum_i, sum_1);
if(mid < qr) query_i1(x->ch[1], y->ch[1], mid+1, r, ql, qr, sum_i, sum_1);
}
int check(int l, int r)
{
for(int h = 31; h; h--)
{
if(((sum[l]>>(h-1))&1)^((a[l]>>(h-1))&1)){if(f[r][h][1]-f[l][h][1] > 0) return 0;}
else {if(f[r][h][0]-f[l][h][0] > 0) return 0;}
}
return 1;
}
int find_bit(int x)
{
for(int h = 1<<30, i = 31; h; h >>= 1, i--)
if(x & h) return i;
return 0;
}
void main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
sum[i] = sum[i-1] ^ a[i];
memcpy(f[i], f[i-1], sizeof(f[i]));
int h = find_bit(a[i]);
f[i][h][(sum[i]>>(h-1))&1]++;
}
for(int i = 1; i <= n; i++)
{
int l = i, r = n;
for(; l < r; )
{
int mid = (l+r+1)>>1;
if(check(i,mid)) l = mid;
else r = mid - 1;
}
pos[i] = l;
}
init(); for(int i = 1; i <= n; i++) insert(root[i-1], root[i] = newseg(), 1, n, pos[i], pos[i]-i+1, i-1);
int qcnt; ll ans = 0; scanf("%d",&qcnt);
for(; qcnt--; )
{
int l, r; scanf("%d%d",&l,&r);
l = (l+ans)%n+1; r = (r+ans)%n+1;
if(l > r) swap(l, r);
ans = 0; ll sum_i = 0, sum_1 = 0;
ans += query_v(root[l-1], root[r], 1, n, l, r);
if(r < n) query_i1(root[l-1], root[r], 1, n, r+1, n, sum_i, sum_1);
ans += r*sum_1-sum_i;
printf("%lld\n",ans);
}
}
}
int main()
{
runzhe2000::main();
}