题目链接:https://ac.nowcoder.com/acm/contest/1114/E
题意:给你n个数和Q次查询,每次查询问你区间[L,R]内使得a[l] ^ … ^ a[r] == 0的最小的区间长度。
思路:看了好多博客才看懂的一道题。首先我们先预处理出对于每个i,离它最近的一个j,并用pre数组记录,及pre[i] = j,使得a[j] ^ … ^ a[i] == 0。至于如何通过一次for循环将这个预处理出来呢?
我们考虑一下异或的性质,相同的书异或为0,那么我们就可以用一个pos数组将每一个前缀异或和出现的位置给记录下来,那么后面我们每一次求出一个异或和之后我们都查询一下pos[sum]是否为-1,如果不是,那么更新pre[i] = pre[sum] + 1;
这是因为
a[1] ^ … ^ a[pre[sum]] = sum;
a[1] ^ … ^ a[i] = sum;
将以上两式异或起来,就可以得到 a[pre[sum] + 1] ^ … ^ a[i] = 0;
代码如下:
memset(pos,-1,sizeof(pos)); //初始化
int sum = 0;
pos[0] = 0;
for(int i = 1 , x ; i <= n ; i++) {
scanf("%d",&x);
sum ^= x;
if(pos[sum] != -1) pre[i] = pos[sum] + 1;
else pre[i] = -1;
pos[sum] = i;
}
之后便是离线查询啦。先将所有的查询用一个结构体存下来,之后按照右端点排序,然后从1开始遍历,每次如果pre[i] != -1,就在线段树中将pre[i] 的值修改为 i - pre[i] + 1。之后用一个while循环将每一个右端点为i的答案更新。代码如下:
for(int i = 1 ; i <= n ; i++) {
if(pre[i] != -1) {
update(pre[i] , i - pre[i] + 1 , 1 , n , 1);
}
while(a[cnt].r == i) {
ans[a[cnt].id] = query(a[cnt].l,a[cnt].r,1,n,1);
cnt++;
}
}
总的代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l , m ,rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 5e5 + 7;
const int INF = 0x3f3f3f3f;
struct node {
int l,r;
int id;
}a[maxn];
bool cmp(node aa,node bb) {
return aa.r < bb.r;
}
int MIN[maxn << 2];
void push_up(int rt) {
MIN[rt] = min(MIN[rt<<1],MIN[rt<<1|1]);
}
void build(int l,int r,int rt) {
MIN[rt] = INF;
if(l == r) return ;
int m = (l + r) >> 1;
build(lson) , build(rson);
}
void update(int x,int y,int l,int r,int rt) {
if(l == r) {
MIN[rt] = y;
return ;
}
int m = (l + r) >> 1;
if(x <= m) update(x,y,lson);
else update(x,y,rson);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt) {
if(L <= l && r <= R) {
return MIN[rt];
}
int ans = INF;
int m = (l + r) >> 1;
if(L <= m) ans = min(ans,query(L,R,lson));
if(R > m) ans = min(ans,query(L,R,rson));
return ans;
}
int pos[maxn << 2] , pre[maxn << 2];
int ans[maxn];
int main() {
int n,Q;
while(~scanf("%d%d",&n,&Q)) {
memset(pos,-1,sizeof(pos));
int sum = 0;
pos[0] = 0;
for(int i = 1 , x ; i <= n ; i++) {
scanf("%d",&x);
sum ^= x;
if(pos[sum] != -1) pre[i] = pos[sum] + 1;
else pre[i] = -1;
pos[sum] = i;
}
for(int i = 1 ; i <= Q ; i++) {
scanf("%d%d",&a[i].l,&a[i].r);
a[i].id = i;
}
sort(a+1,a+Q+1,cmp);
build(1,n,1);
int cnt = 1;
for(int i = 1 ; i <= n ; i++) {
if(pre[i] != -1) {
update(pre[i] , i - pre[i] + 1 , 1 , n , 1);
}
while(a[cnt].r == i) {
ans[a[cnt].id] = query(a[cnt].l,a[cnt].r,1,n,1);
cnt++;
}
}
for(int i = 1 ; i <= Q ; i++) {
printf("%d\n",ans[i] == INF ? -1 : ans[i]);
}
}
return 0;
}