CodeForces 1000F One Occurrence( 离线处理+线段树解法)
You are given an array a consisting of n integers, and q queries to it. i-th query is denoted by two integers li and ri. For each query, you have to find any integer that occurs exactly once in the subarray of a from index li to index ri (a subarray is a contiguous subsegment of an array). For example, if a=[1,1,2,3,2,4], then for query (li=2,ri=6) the subarray we are interested in is [1,2,3,2,4], and possible answers are 1, 3 and 4; for query (li=1,ri=2) the subarray we are interested in is [1,1], and there is no such element that occurs exactly once.
Can you answer all of the queries?
The first line contains one integer n(1≤n≤5⋅105).
The second line contains n integers a1,a2,…,an (1≤ai≤5⋅105).
The third line contains one integer q(1≤q≤5⋅105).
Then q lines follow, i-th line containing two integers li and ri representing i-th query (1≤li≤ri≤n).
Answer the queries as follows:
If there is no integer such that it occurs in the subarray from index li to index ri exactly once, print 0. Otherwise print any such integer.
大致题意:给你一个固定的数列a,然后q个询问,每个询问给出一个区间,问你区间内是否有恰好出现一次的数字,如果有输出任意一个,否则输出0。
这题主要方法就是仿照17年HDU多校有一道题的做法,HDU 6070。其实也只是用了其中的一个思想,也即用每一个数字把区间分段。对于每一个区间[1,r]中的最右边的一个数字i,我都可以记录一个pos[i],表示数字i在区间[1,r]中上一个出现的位置。这里最右边指的是,同一个数字i,可能在区间中出现多次,最后那次是我们想要的。求出了这个pos,我们可以发现,对于一个询问[l,r],如果区间中所有有效的pos的数值的最小值小于l,那么可以说明存在一个数字x,在区间里面出现过,而且他上一次出现的位置是在区间外面,这个数字就是答案。
显然,我们可以看出,这个最右边是与这个r的选取有关。所以我们得顺序枚举这个r,同时对询问按照右端点进行排序,离线处理。但是从r更新到r+1的时候要注意,如果a[r+1]之前出现过,那么他的上一次出现位置就是pos[a[r]],我们把树中位置r更新为pos[a[r]]的同时,别忘了要把位置pos[a[r]]的数值消除。由于只是求最小值,所以把位置pos[a[r]]的数值变成INF即可。具体见代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 500010
using namespace std;
struct query{int l,r,id;} Q[N];
int n,q,a[N],pos[N],ans[N];
typedef pair<int,int> PII;
struct ST
{
struct node{int l,r;PII min;} tree[N<<2];
inline void build(int i,int l,int r)
{
tree[i].r=r;
tree[i].l=l;
if (l==r) return;
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
}
inline void update(int i,int pos,int pre)
{
if (tree[i].l==tree[i].r)
{
tree[i].min=PII(pre,pos);
return;
}
int mid=(tree[i].l+tree[i].r)>>1;
if (mid>=pos) update(i<<1,pos,pre);
else if (mid<pos) update(i<<1|1,pos,pre);
tree[i].min=min(tree[i<<1].min,tree[i<<1|1].min);
}
inline PII getmin(int i,int l,int r)
{
if (tree[i].l==l&&tree[i].r==r) return tree[i].min;
int mid=(tree[i].l+tree[i].r)>>1;
if (mid>=r) return getmin(i<<1,l,r);
else if (mid<l) return getmin(i<<1|1,l,r);
else return min(getmin(i<<1,l,mid),getmin(i<<1|1,mid+1,r));
}
} seg;
bool cmp(query a,query b)
{
return a.r==b.r?a.l<b.l:a.r<b.r;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].id=i;
}
seg.build(1,1,n);
sort(Q+1,Q+1+q,cmp);
for(int i=1,j=1;i<=n;i++)
{
if (pos[a[i]]) seg.update(1,pos[a[i]],INF);
seg.update(1,i,pos[a[i]]);
for(;Q[j].r==i&&j<=q;j++)
{
PII tmp=seg.getmin(1,Q[j].l,Q[j].r);
if (tmp.first<Q[j].l) ans[Q[j].id]=a[tmp.second];
}
pos[a[i]]=i;
}
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
return 0;
}
上一篇: Linux 压缩和解压命令
下一篇: Cows POJ - 2481