牛客练习赛53 E.老瞎眼 pk 小鲜肉(离线+BIT单点修改)

题目

老瞎眼有一个长度为 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;
}
发布了467 篇原创文章 · 获赞 53 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/103264222