这题我是离线做的
设i位置的数上次出现的位置是pre[i](如果第一次出现那就是0)
可以想到,用线段树维护一个区间的pre的最小值,如果它小于区间左端点,那这个数就是一个合法的答案
但直接这样做是错的
考虑1,2,3,4,[1,1],5,虽然前一个1的pre在区间外面,但他后面还有一个1啊
所以可以按照询问的右端点排序,推着来维护这个最小值
具体来说,对于i,先把i位置的值改成pre[i],然后如果有pre[i],那把pre[i]位置的值改成inf(一开始都要初始化成inf)
然后再查的话,我查到的就都是这个区间里的最后一次出现的那个数了,就不会有锅
1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace std; 5 typedef long long ll; 6 const int maxn=5e5+10; 7 8 inline ll rd(){ 9 ll x=0;char c=getchar();int neg=1; 10 while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();} 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x*neg; 13 } 14 15 int N,Q,pre[maxn],A[maxn],tmp[maxn],ans[maxn]; 16 pa mn[maxn<<2]; 17 struct Node{ 18 int l,r,i; 19 }que[maxn]; 20 21 inline bool cmp(Node a,Node b){return a.r<b.r;}; 22 23 inline void update(int p){ 24 mn[p]=min(mn[p<<1],mn[p<<1|1]); 25 } 26 27 void change(int p,int l,int r,int x,int y){ 28 if(l==r) mn[p]=make_pair(y,x); 29 else{ 30 int m=l+r>>1; 31 if(x<=m) change(p<<1,l,m,x,y); 32 else change(p<<1|1,m+1,r,x,y); 33 update(p); 34 } 35 } 36 37 pa query(int p,int l,int r,int x,int y){ 38 if(x<=l&&r<=y) return mn[p]; 39 int m=l+r>>1;pa re=make_pair(N+1,0); 40 if(x<=m) re=query(p<<1,l,m,x,y); 41 if(y>=m+1) re=min(re,query(p<<1|1,m+1,r,x,y)); 42 return re; 43 } 44 45 int main(){ 46 int i,j,k; 47 N=rd(); 48 for(i=1;i<=N;i++){ 49 A[i]=rd(); 50 pre[i]=tmp[A[i]],tmp[A[i]]=i; 51 }Q=rd(); 52 for(i=1;i<=Q;i++){ 53 que[i].l=rd(),que[i].r=rd(),que[i].i=i; 54 }sort(que+1,que+Q+1,cmp); 55 CLR(mn,127); 56 for(i=1,j=1;i<=Q;i++){ 57 for(;j<=que[i].r&&j<=N;j++){ 58 if(pre[j]) change(1,1,N,pre[j],N+1); 59 change(1,1,N,j,pre[j]); 60 } 61 pa re=query(1,1,N,que[i].l,que[i].r); 62 if(re.first<que[i].l) ans[que[i].i]=A[re.second]; 63 } 64 for(i=1;i<=Q;i++) printf("%d\n",ans[i]); 65 return 0; 66 }
来源:https://www.cnblogs.com/Ressed/p/9863482.html