题意:就是给你一些区间,每次有q个询问,每次询问一个区间的所有子区间的抑或和,数据范围都是100000。
思路:首先求一下抑或和前缀,然后你会发现对于一个区间的最后结果就是区间选两个位置的数抑或在一起,考虑拆位,抑或就是这一为的数字不同的时候贡献为1,然后对于每一位对该区间的贡献就是这一位在该区间0的个数和1的个数乘在一起,当然还要考虑比l-1这个数字,这样保证边界是可以取到的,我首先想的思路是线段树,想了一下感觉自己是对的,但是仔细想想发现多算了一些情况,所以不太对,所以这个思路还得在考虑考虑,这个思路是上交大佬给我提供的,上交大佬说这些都是做题的直觉,应该就是条件反射,看到题目中的一些条件,就会想到一些处理方法,这些都是在做题的时候总结出来的。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll=long long ;
ll A[100000+10],B[100000+10][35];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,q;
scanf("%d%d",&n,&q);
memset(B,0,sizeof(B));
for(int i=1; i<=n; i++)
{
scanf("%lld",&A[i]);
A[i]^=A[i-1];
ll x=A[i];
int t=0;
// cout<<"ewqr"<<x<<endl;
while(x)
{
B[i][t++]=x%2;
x/=2;
}
for(int j=0; j<31; j++)
B[i][j]+=B[i-1][j];
}
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
ll sum=0;
for(int i=0; i<30; i++)
{
sum+=(B[r][i]-B[l-1][i])*(r-l+2-(B[r][i]-B[l-1][i]))*(1ll<<i);
// cout<<B[r][i]<<" "<<B[l-1][i]<<endl;
}
printf("%lld\n",sum);
}
}
}
/*
1
3 1
1 2 3
1 3
*/