牛客练习赛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;
}

 

posted @ 2019-10-12 20:08  wilxx  阅读(126)  评论(0编辑  收藏  举报