https://codeforces.com/contest/1511/problem/G
雅米老师教了我一手倍增做这题,奥妙重重,比题解分块高到不知道哪里去了
设f[k][i]表示从i列开始向后的连续2^k的块中所有点到i的距离的异或和
f[k][i]=f[k-1][i]^f[k-1][i+2^(k-1)],但是我们发现i+2^(k-1)到i+2^k-1这一段的所有点其实都长度增加了2^(k-1),且由于f[k-1]中所有连续块的长度最多是2^(k-1),所以他们到左边界的值最大是2^(k-1)-1的,所以增加2^(k-1)对于本身异或和是独立的
所以如果i+2^(k-1)到i+2^k-1这一段中有奇数个点的话,f[k][i]^=1<<(k-1)
最后求答案的时候也是,从l开始倍增,每次l+=1<<k,然而从当前l到实际的r中所有点到实际 l的距离都多增加了2^k,所以后面如果还有奇数个点的话,就要res^=2^k
#include<bits/stdc++.h>
using namespace std;
const int maxl=2e5+10;
int n,m,q;
int c[maxl],sum[maxl];
int f[21][maxl];
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&c[i]);
sum[c[i]]^=1;
}
for(int i=1;i<=m;i++)
sum[i]^=sum[i-1];
for(int k=1;k<=20;k++)
for(int i=1;i+(1<<k)-1<=m;i++)
{
int r=i+(1<<k)-1;
f[k][i]=f[k-1][i]^f[k-1][i+(1<<(k-1))];
if(sum[r]^sum[i+(1<<(k-1))-1])
f[k][i]^=1<<(k-1);
}
}
inline void mainwork()
{
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int l,r,res=0;scanf("%d%d",&l,&r);
for(int k=20;k>=0;k--)
if(l+(1<<k)-1<=r)
{
res^=f[k][l],l+=(1<<k);
if(sum[r]^sum[l-1])
res^=1<<k;
}
putchar(res?'A':'B');
}
}
int main()
{
prework();
mainwork();
return 0;
}