题意:给定序列a ,q次询问 每次询问要求[l,r]区间任意一个只出现过一次的数 没有则输出0 。
分析:这题和这题十分类似,
我们先分析对于右端点固定的区间,即:求出[1,r]的某个[l,r]区间只出现过一次的数。
我们用last[i]维护i上一次出现的位置,那么对于序列last[a[i]]
(i映射成last[a[i]]),我们查询[l,r]内是否存在只出现过一次的数就等价于last[a[i]]在[l,r]区间是否存在小于l的值, 根据贪心我们可以用线段树维护序列last[a[i]]的区间最小值。 每次询问就查询线段树[l,r]内最小值是否小于l即可。
这题右端点不固定,我们可以对每个前缀建线段树。每次询问取出r版本线段树进行查询即可。
用动态开点维护最小值的时候,可以统一把虚点设成INF。然后正常的pushup就行。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 5e5+5;
const int mx = 40;
const int mod = 1e9+5;
const ll inf = 34359738370;
const int INF = 1e9+5;
//给定序列a ,q次询问 每次询问要求[l,r]区间任意一个只出现过一次的数 没有则输出0
//和求子区间不同种类个数那题是差不多的技巧
//last[i]表示i上一次出现的位置 线段树维护区间内的数上一次出现的最远位置 第一次出现则为0
//固定右端点的话按右端点排序 离线查询
//每次询问 查询的时候查root[r]这棵树的[l,r]区间内的最小值 如果小于l就有解
struct node
{
int v,index;//区间内的数上一次出现最远的位置 这个数的位置
/* friend bool operator<(const node &a,const node&b)
{
if(a.v != b.v) return a.v<b.v;
else return a.index<b.index;
}*/
bool operator < (const node &a)const
{
if(v != a.v) return v<a.v;
else return index<a.index;
}
}tree[maxn*mx];
int lc[maxn*mx],rc[maxn*mx],cnt=0,root[maxn];
int last[maxn];
void updata(int &rt,int last,int l,int r,int pos,int v)//pos位置的值设成v
{
rt=++cnt;
tree[rt]=tree[last];
lc[rt]=lc[last],rc[rt]=rc[last];
if(l == r)
{
tree[rt].index=pos;
tree[rt].v=v;
return ;
}
int mid=(l+r)>>1;
if(pos<=mid) updata(lc[rt],lc[last],l,mid,pos,v);
else updata(rc[rt],rc[last],mid+1,r,pos,v);
tree[rt]=min(tree[lc[rt]],tree[rc[rt]]);
}
node query(int rt,int l,int r,int vl,int vr)//第rt棵树 [vl,vr]内的最小值
{
if(vl<=l && r<=vr) return tree[rt];
int mid=(l+r)>>1;
if(vr<=mid) return query(lc[rt],l,mid,vl,vr);
else if(vl>mid) return query(rc[rt],mid+1,r,vl,vr);
node t1=query(lc[rt],l,mid,vl,vr),t2=query(rc[rt],mid+1,r,vl,vr);
return min(t1,t2);
}
int n,m,a[maxn];
int main()
{
tree[0].v=INF;//把所有的虚点设成INF
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",a+i);
if(!last[a[i]])
{
updata(root[i],root[i-1],1,n,i,0);
}
else
{
int temp;
updata(temp,root[i-1],1,n,last[a[i]],INF);//设成INF 消除上一个位置对当前位置的影响
updata(root[i],temp,1,n,i,last[a[i]]);
}
last[a[i]]=i;
}
scanf("%d",&m);
while(m--)
{
int l,r;
scanf("%d %d",&l,&r);
node x=query(root[r],1,n,l,r);
if(x.v >= l) puts("0");
else printf("%d\n",a[x.index]);
}
return 0;
}