1000F.One Ocurrence(可持久化线段树+思维)
这题很妙。
多去完成这种级别的题目,建模能力才会真正得到提高。
题解干完springboot活补。
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
const int maxn=5e5+100;
//维护每个点后面的最小位置
//什么点在区间内只出现了一次
//用主席树维护
//下标:最近一次出现的位置
//权值:上一次出现的位置的最大值
//一个版本的主席树只保存最近一次出现的位置
//单点更新
int n,a[maxn],q;
const int M=maxn*50;
int c[M],tot,lson[M],rson[M],T[M];
int pp[M];//表示区间最大值下标的位置
int build (int l,int r) {
int rt=++tot;
c[rt]=0;
pp[rt]=0;
if (l==r) return rt;
int mid=(l+r)>>1;
lson[rt]=build(l,mid);
rson[rt]=build(mid+1,r);
return rt;
}
int up (int root,int l,int r,int p,int v) {
int newRoot=++tot;
if (l==r) {
c[newRoot]=v;
pp[newRoot]=p;
return newRoot;
}
int mid=(l+r)>>1;
if (p<=mid) {
lson[newRoot]=up(lson[root],l,mid,p,v);
rson[newRoot]=rson[root];
}
else {
rson[newRoot]=up(rson[root],mid+1,r,p,v);
lson[newRoot]=lson[root];
}
c[newRoot]=max(c[lson[newRoot]],c[rson[newRoot]]);
if (c[newRoot]==c[lson[newRoot]]) pp[newRoot]=pp[lson[newRoot]];
else pp[newRoot]=pp[rson[newRoot]];
return newRoot;
}
pair<int,int> query (int root,int l,int r,int L,int R) {
//查找最近一次出现位置的最大上上次出现位置
if (l>=L&&r<=R) return make_pair(c[root],pp[root]);
int mid=(l+r)>>1;
pair<int,int> ans=make_pair(0,0);
if (L<=mid) ans=max(ans,query(lson[root],l,mid,L,R));
if (R>mid) ans=max(ans,query(rson[root],mid+1,r,L,R));
return ans;
}
int nxt[maxn];
int pre[maxn];
int main () {
n=read();
for (int i=1;i<=n;i++) a[i]=read();
for (int i=n;i>=1;i--) {
nxt[i]=pre[a[i]];
pre[a[i]]=i;
}
q=read();
T[n+1]=build(1,n);
for (int i=n;i>=1;i--) {
if (nxt[i]) {
int tt=up(T[i+1],1,n,nxt[i],0);
T[i]=up(tt,1,n,i,nxt[i]);
}
else {
T[i]=up(T[i+1],1,n,i,1e9);
}
}
while (q--) {
int l=read();
int r=read();
pair<int,int> tt=query(T[l],1,n,l,r);
int ans=tt.second;
if (tt.first<=r) ans=0;
printf("%d\n",a[ans]);
}
}