牛客练习赛53 老瞎眼 pk 小鲜肉[思维+离线+线段树]

题目大意

给定一个序列,q个查询
查询(l,r)内 异或值=0 的最小区间

题目分析

考虑对序列求一个前缀异或和
那么 每个点找到与自己相同的最近的点的位置,就是每个点作为右端点 =0 的最小区间。

所有的查询区间按照右端点排序

然后我们枚举1,n所有点,在线段树 该店对应左端点的位置插入这个区间长度。
对于所有右端点为i的询问 查询(l,r)区间内的最小值即可

代码详解
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int maxn =6e5+50;
const int maxm =2e6+60;
int n,q;
struct node
{
	int ans=inf;
	int id;
	int l,r;
}t[maxn];
int a[maxm];
int pre[maxm];
int last[maxm];
int le[maxm];
bool cmp(node a,node b)
{
	if(a.r==b.r) return a.l>b.l;
	return a.r<b.r;
}
struct Node
{
	//int data;
	int l,r;
	int mn;
}tree[maxn*4];
void pushup(int root)
{
	tree[root].mn = min(tree[root*2].mn,tree[root*2+1].mn);
}
void build(int root,int l,int r)
{
	if(r<l)return;
	tree[root].l = l; tree[root].r = r;
	if(l==r) 
	{
		tree[root].mn = inf;
		return;
	}
	int mid = (l+r)/2;
	build(root*2,l,mid);
	build(root*2+1,mid+1,r);
	pushup(root);
}
void update(int root,int k,int val)
{
	int l = tree[root].l; 
	int r = tree[root].r;
	if(l==r) 
	{
		tree[root].mn =val;
		return;
	}
	int mid = (l+r)/2;
	if(mid<k) update(root*2+1,k,val);
	else update(root*2,k,val);
	pushup(root);
	//cout<<tree[root].mn
}
int query(int root,int st,int ed)
{
	int l = tree[root].l;
	int r = tree[root].r;
//	cout<<l<<" "<<r<<" "<<tree[root].mn<<endl;
	if(st<=l&&ed>=r) return tree[root].mn;
	else if(st>r||ed<l) return inf;
	int ans = inf;
	ans = min(ans,query(root*2,st,ed));
	ans = min(ans,query(root*2+1,st,ed));
	return ans;
//	if(tree[root].l == tree[root].r)
}
bool cmp2(node a,node b)
{
	return a.id<b.id;
}
int main()
{
	
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	pre[0] = 0;
	memset(last,-1,sizeof(last)); 
	last[0] = 0;
	for(int i=1;i<=n;i++)
	{
		  pre[i]=pre[i-1]^a[i];
		  le[i] = last[pre[i]];
		  last[pre[i]] = i;
	}
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&t[i].l,&t[i].r);
		t[i].id= i;
	}
	sort(t+1,t+1+q,cmp);
	build(1,1,n);
	for(int i=1;i<=q;i++)
	{
		int r = t[i].r;
		if(le[r]!=-1)
		{
			update(1,le[r]+1,r-le[r]);
		}
		t[i].ans = query(1,t[i].l,t[i].r);
	}
	sort(t+1,t+1+q,cmp2);
	for(int i=1;i<=q;i++)
	{
		if(t[i].ans<maxm)
		printf("%d\n",t[i].ans);
		else printf("-1\n");
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值