题号 NC50444
名称 老瞎眼 pk 小鲜肉
来源 牛客练习赛53
戳我进入往期每日一题汇总贴~
往期每日一题二期题单
如果你在题库做题时遇到了喜欢的题目,欢迎推荐给邓老师~ 点击查看详情
每日一题QQ群:659028468
题解
作者:nagisa_菜鸡
看到题目,我想大家第一个想到的就是前缀异或和,因为这种询问一整段的异或和的一半都需要这样处理,不然复杂度太高。
之后,题目要询问的就是找到在区间[L,R]中的存在的点sum[l]==sum[r],使得r-l+1最小。若是考虑直接让值对应整个[l,r]区间则会很麻烦,所以,考虑转化为单点维护。
考虑单点维护,则有两个选择:要么放在l,要么放在r。
那么,我们先试个错误答案,若我们放在r,那么,我们在查询的时候就会遇到麻烦:我们在查询后面的点的时候,我们找不到一个方法确定查询到的值到底是不是属于[L,R]区间的,所以,不能选择r存储。
若选择了l,我们就有另一种方法了,那就是离线。我们将询问全部按照r排序,之后,我们枚举r(设现在枚举到的r为i),每次移动后,查询目前的sum[i]是否之前出现过,若有出现过,则将这个区间的贡献l-r+1作为l的贡献挂在点l处,丢进线段树里。每次查询的时候,我们只根据询问的[L,R]进行查询,若L>=l,则不会查询到l的贡献。若查询到了,则查询到的值一定是属于[L,i](也就是[L,R],此时枚举的i为R)的。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 1e9
template<typename T>
void read(T&x){
x=0;
char ch=getchar();
ll f=1;
while(!isdigit(ch)){
if(ch=='-')f*=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
template<typename T>
void write(T x){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
//===========================================================
const int maxn=500000+100;
const int maxm=(1<<20)+100;
#define lson (rt<<1)
#define rson (rt<<1|1)
struct node{
int l,r,val;
}tree[maxn<<2];
int flag;
void push_up(int rt){
//if(flag)cerr<<tree[rt].val<<" "<<tree[rt].l<<" "<<tree[rt].r<<endl;
tree[rt].val=min(tree[rson].val,tree[lson].val);
}
void build(int l,int r,int rt){
tree[rt].l=l;tree[rt].r=r;
if(l==r){
tree[rt].val=inf;
return ;
}
int m=(l+r)>>1;
build(l,m,lson);
build(m+1,r,rson);
push_up(rt);
}
void modify(int ql,int qr,int rt,int val){
int l=tree[rt].l,r=tree[rt].r;
if(ql<=l&&r<=qr){
tree[rt].val=val;
return ;
}
int m=(l+r)>>1;
if(ql<=m)modify(ql,qr,lson,val);
if(qr>m) modify(ql,qr,rson,val);
push_up(rt);
}
int query(int ql,int qr,int rt){
int l=tree[rt].l,r=tree[rt].r;
if(ql<=l&&r<=qr){
//cerr<<tree[rt].val<<" "<<tree[rt].l<<" "<<tree[rt].r<<endl;
return tree[rt].val;
}
int res=inf;
int m=(l+r)>>1;
if(ql<=m)res=min(res,query(ql,qr,lson));
if(qr>m)res=min(res,query(ql,qr,rson));
push_up(rt);
return res;
}
struct Q{
int l,id;
Q(int L,int I){
l=L;
id=I;
}
};
vector<Q>que[maxn];
int n,q,a[maxn];
int ans[maxn];
int pre[maxm];
signed main(){
//freopen("in.txt","r",stdin);
scanf("%d %d",&n,&q);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)a[i]^=a[i-1];
for(int i=1;i<=q;i++){
int x,y;
scanf("%d %d",&x,&y);
//cerr<<x<<" "<<y<<endl;
que[y].push_back(Q(x,i));
//que.push_back(Q(x,y,i));
}
build(1,n,1);
memset(pre,-1,sizeof(pre));
for(int i=1;i<=n;i++){
pre[a[i-1]]=i;
int L=pre[a[i]];
if(~L)modify(L,L,1,i-L+1);
for(auto x:que[i]){
//cerr<<"yes"<<endl;
ans[x.id]=query(x.l,i,1);
}
}
for(int i=1;i<=q;i++){
printf("%d\n",ans[i]==inf?-1:ans[i]);
}
return 0;
}欢迎各位大佬来做题写题解,也欢迎大家踊跃在当日讨论贴中提问!
活动奖励:
在牛客博客中写出题解,并回复地址
审核通过可获得(依据题目难度和题解的内容而定)
本道题目12月24日中午12:00之前写的题解有获得牛币资格~
牛客博客开通方式
- 如何开通牛客博客:https://www.nowcoder.com/discuss/202952
- 如何使用博客搬家功能:进入博客--->设置--->底部博客搬家
- 如果你对牛客博客有任何意见或建议:牛客博客意见反馈专贴

全部评论
(6) 回帖