牛客练习赛53-E老瞎眼 pk 小鲜肉
不太会啊。。(太难了)
由异或性质,如果异或前缀和sum[i]=sum[j];
显然sum[i]^sum[j]=0
读入a[i]时直接与a[i-1]异或求出来a[i]的位置存的便不是原先的a[i]而是sum[i]了。
每个点找到与自己相同的靠左的最近的点的位置,就是每个点作为右端点 =0 的最小区间。
枚举1,n所有点,在树状数组对应左端点的位置插入这个区间长度。
对于所有右端点为i的询问 查询(l,r)区间内的最小值即可
#include<bits/stdc++.h> using namespace std; int n,q; int a[500010]; struct node{ int num; int l; int r; }ask[500010]; int c[500010],pre[2000000]; int ans[500010]; bool com(const node &x,const node &y){ return x.r<y.r; } void add(int x,int ad){ for(;x;x-=(x&(-x)))c[x]=min(c[x],ad); } int query(int x){ int ret=1e9; for(;x<=n;x+=(x&(-x)))ret=min(ret,c[x]); return ret; } int main(){ memset(c,0x3f,sizeof(c)); scanf("%d%d",&n,&q); n++; a[1]=0; for(int i=2;i<=n;i++){ scanf("%d",&a[i]); a[i]^=a[i-1]; } for(int i=1;i<=q;i++){ ask[i].num=i; scanf("%d%d",&ask[i].l,&ask[i].r); ask[i].l++;//从2开始读入的a[i]; ask[i].r++; } sort(ask+1,ask+q+1,com); int now=1; for(int i=1;i<=n;i++){ if(pre[a[i]]){ add(pre[a[i]],i-pre[a[i]]);//对应左端点的位置插入这个区间长度。 } pre[a[i]]=i; while(now<=q&&ask[now].r==i){ ans[ask[now].num]=query(ask[now].l-1); now++; } } for(int i=1;i<=q;i++){ printf("%d\n",ans[i]==1e9?-1:ans[i]); } return 0; }
作者:wilxx
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.