转载自:http://blog.csdn.net/zsc2014030403015/article/details/51307922
题意:
给出你n个数,m次查询,要你找出[L,R]异或为k的子区间有多少个。
思路:
这题思路是首先求出前缀和,所以就会有sum[L-1]^sum[R]==k的公式,但是左边是两个都是不清楚值的,所以要转变一下,
变为sum[R]^k==sum[L-1],这样子我只要求出现在存在多少个sum[L-1]就知道有多少个可以和sum[k]异或为k的了
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-9
#define maxn 1000100
#define MOD 1000000007
long long Ans[maxn],ans;
int n,m,k;
int sum[maxn],num[1<<20],sz;
struct node
{
int l,r,id;
bool operator < (const node &a)const
{
if((l/sz) == (a.l/sz))
return r < a.r;
return l < a.l;
//return ((l/sz) == (a.l/sz) && r < a.r) || l < a.l; //TLE???
}
}a[maxn];
void add(int x)
{
<span style="white-space:pre"> </span>/*
<span style="white-space:pre"> </span>当前sum[L-1]^sum[R]=k,所以只要知道当前sum[L-1]有多少个
<span style="white-space:pre"> </span>即有多少个是在[L-1,R]区间异或是等于k的
<span style="white-space:pre"> </span>*/
ans += num[sum[x]^k];
num[sum[x]]++; //增加当前前缀和个数
<span style="white-space:pre"> </span> //这里后来才加是为了防止增加为本身
}
void sub(int x)
{
num[sum[x]]--; //一个数有可能异或后还是本身,所以要先减去本身
ans -= num[sum[x]^k];
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t,C = 1;
//scanf("%d",&t);
while(scanf("%d%d%d",&n,&m,&k) != EOF)
{
memset(num,0,sizeof(num));
sz = sqrt(1.0*n);
sum[0] = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d",&sum[i]);
sum[i] ^= sum[i-1];
}
for(int i = 1; i <= m; i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].id = i;
}
sort(a+1,a+m+1);
int l = 1,r = 0;
ans = 0;
for(int i = 1; i <= m; i++)
{
while(r < a[i].r)
add(++r);
while(r > a[i].r)
sub(r--);
while(l > a[i].l-1)
add(--l);
while(l < a[i].l-1)
sub(l++);
Ans[a[i].id] = ans;
}
for(int i = 1; i <= m; i++)
printf("%lld\n",Ans[i]);
}
return 0;
}