题目
老瞎眼有一个长度为 n 的数组 a,为了为难小鲜肉,他准备了 Q 次询问,每次给出 一个区间[L,R],他让小鲜肉寻 找一对 l,r 使L<=l<=r<=R 且 a[l]^a[l+1]^a[l+2]...^a[r]=0,老瞎眼只让他回答r-l+1 最小是多少,若没有符合条件的 l,r 输出”-1”。
1<=n,Q<=500000,0<=a[i]<=1000000,1<=L<=R<=n
思路来源
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=41387922
题解
考虑已经处理好若干条线段了,
如何统计完整包含在线段内的最短的线段的长度,
其实和徐州网络赛的区间统计点对(l,r)对的答案算在r的单点上很像,
把线段区间[l,r]的贡献也只算在r的单点上,对单点保留区间长度的较小值
那么就相当于询问q条线段,n个端点,每条线段上覆盖的点最小的值
排序离线,一边插入点,一边询问线段,取最小值回答即可
注意一些pre[]和las[]初始化,思路来源的代码可以说非常巧妙了
代码
#include<bits/stdc++.h>
using namespace std;
const int M=(1<<20)+5,N=5e5+10;
int n,q,now,pre[M],las[M];
int a[N],rk[N],tr[N],res[N];
int cmp(int a,int b)
{
return pre[a]>pre[b];
}
struct node
{
int l,r,id;
}e[N];
bool operator<(node a,node b)
{
return a.l>b.l;
}
void upd(int x,int v)
{
for(int i=x;i<=n;i+=i&-i)
tr[i]=min(tr[i],v);
}
int ask(int x)
{
int ans=n+1;
for(int i=x;i>0;i-=i&-i)
ans=min(ans,tr[i]);
return ans;
}
int main()
{
scanf("%d%d",&n,&q);
memset(las,-1,sizeof las);
las[0]=0;
memset(tr,0x3f,sizeof tr);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
a[i]^=a[i-1];
pre[i]=las[a[i]];
las[a[i]]=i;
rk[i]=i;
}//(pre[i],rk[i]]
for(int i=1;i<=q;++i)
{
e[i].id=i;
scanf("%d%d",&e[i].l,&e[i].r);
}
sort(rk+1,rk+n+1,cmp);
sort(e+1,e+q+1);
now=1;
for(int i=1;i<=q;++i)
{
while(now<=n&&pre[rk[now]]>=e[i].l-1)
{
upd(rk[now],rk[now]-pre[rk[now]]);
now++;
}
res[e[i].id]=ask(e[i].r);
if(res[e[i].id]>n)res[e[i].id]=-1;
}
for(int i=1;i<=q;++i)
printf("%d\n",res[i]);
return 0;
}