题目:
题意:
不强制在线,询问q个区间内只出现一次的数字,输出这个数字(任意一个)
题解:
一棵线段树就行了,从左往右依次把每个位置的数字&pre的位置加上,线段树的节点表示位置
考虑以i为右节点,左节点为l(很多个)的情况。
我们线段树维护每个节点的pre的min,如果min < l,说明这个数字在l~r中只出现了一次,就是个合法的数字,那么我们区间查询合法数字就行
但是如果这种情况呢?
2的pre在l的左端,但是3还出现了,就不是个合法的情况
怎么避免呢?
可以选择在加入3的时候,如果他的pre存在(2),就把pre这个位置的值去掉就可以了,设为INF
这样就是一个单点修改,区间查询的线段树了
代码:
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define INF 1e9
const int N=500005;
int ans[N],a[N],pre[N],last[N];
struct hh{int pre,x;hh(int X=0,int Y=0){pre=X; x=Y;}}tree[N*4],hx;
vector<hh>q[N];
bool operator <(hh a,hh b){return a.pre<b.pre;}
void updata(int now){tree[now]=min(tree[now<<1],tree[now<<1|1]);}
void change(int now,int l,int r,int x)
{
if (l==r){tree[now]=hx;return;}
int mid=(l+r)>>1;
if (x<=mid) change(now<<1,l,mid,x);
else change(now<<1|1,mid+1,r,x);
updata(now);
}
void qurry(int now,int l,int r,int lrange,int rrange)
{
if (lrange<=l && rrange>=r) {hx=min(hx,tree[now]);return;}
int mid=(l+r)>>1;
if (lrange<=mid) qurry(now<<1,l,mid,lrange,rrange);
if (rrange>mid) qurry(now<<1|1,mid+1,r,lrange,rrange);
}
int main()
{
int n,Q;scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&Q);
for (int i=1;i<=Q;i++)
{
int x,y;scanf("%d%d",&x,&y);
q[y].push_back((hh){x,i});
}
for (int i=1;i<=n;i++)
{
pre[i]=last[a[i]];
last[a[i]]=i;
}
for (int i=1;i<=n;i++)
{
if (pre[i])
{hx=hh(INF,INF);change(1,1,n,pre[i]);}
hx=hh(pre[i],a[i]);
change(1,1,n,i);
for (int j=0;j<q[i].size();j++)
{
hx=hh(INF,INF);
qurry(1,1,n,q[i][j].pre,i);
if (hx.pre<q[i][j].pre) ans[q[i][j].x]=hx.x;
else ans[q[i][j].x]=0;
}
}
for (int i=1;i<=Q;i++) printf("%d\n",ans[i]);
}