傳送門: 老瞎眼 pk 小鮮肉
題意: 給出一段長度爲n的序列,q次查詢區間(L,R)內異或爲0最短子區間長度。
思路: 假設區間[L,R]異或爲0,那麼[1,L-1]的異或值等於[1,R]的異或值。那麼對於每個點,我們存以它爲右端點的區間異或值爲0的最短區間長度,再將查詢區間按右端點升序排列。然後利用線段樹,從左到右遍歷:在這個點對應最短區間的左端點插入區間長度,如存在右端點等於當前遍歷節點的查詢區間,就去查詢[L,R],因爲此時線段樹上已插入的點都是在他的右端點內,查詢到的點也都在他的左端點內。
代碼:
#include<bits/stdc++.h>
using namespace std;
int a[500010];
int len[1000000*4],pre[500010];
int c[500010*4];
void update(int rt,int l,int r,int pos,int v){
if(l==r){
c[rt]=min(c[rt],v);
return ;
}
int mid=(l+r)/2;
if(pos<=mid) update(rt<<1,l,mid,pos,v);
if(mid<pos) update(rt<<1|1,mid+1,r,pos,v);
c[rt]=min(c[rt<<1],c[rt<<1|1]);
return ;
}
int query(int rt,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr){
return c[rt];
}
int res=INT_MAX;
int mid=(l+r)/2;
if(ll<=mid) res=min(res,query(rt<<1,l,mid,ll,rr));
if(mid<rr) res=min(res,query(rt<<1|1,mid+1,r,ll,rr));
return res;
}
struct ac{
int l,r,id;
}w[500010];
bool cmp(ac a1,ac a2){
return a1.r<a2.r;
}
int ans[500010];
int main(){
int n,Q;
scanf("%d%d",&n,&Q);
int sum=0;
memset(c,0x3f,sizeof c);
memset(len,-1,sizeof len);
memset(pre,-1,sizeof pre);
len[0]=0;
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
sum=sum^a[i];
if(len[sum]!=-1){
pre[i]=i-len[sum];
//cout<<i-pre[i]+1<<" "<<i<<" "<<pre[i]<<endl;
}
len[sum]=i;
}
for(int i=1;i<=Q;++i){
scanf("%d%d",&w[i].l,&w[i].r);
w[i].id=i;
}
sort(w+1,w+1+Q,cmp);
int cnt=1;
for(int i=1;i<=n;++i){
if(pre[i]!=-1){
update(1,1,n,i-pre[i]+1,pre[i]);
}
while(w[cnt].r==i){
ans[w[cnt].id]=query(1,1,n,w[cnt].l,i);
++cnt;
}
}
for(int i=1;i<=Q;++i){
if(ans[i]!=0x3f3f3f3f) printf("%d\n",ans[i]);
else puts("-1");
}
return 0;
}