題解 CF1000F 【One Occurrence】
阿新 • • 發佈:2020-09-08
本題解用於記錄一下一個優秀的東西——懶標記。
題解
可以很輕易的想到莫隊的做法,但是題目讓你輸出的是滿足條件的一個數,而不是滿足條件的數的個數,似乎很難去 \(O(1)\) 轉移。這個時候我們的懶標記就出場了。
我們可以維護一個棧,然後再加數字的時候直接加,但是刪數字的時候在外面刪(維護一個 \(bool\) 陣列),然後回答詢問時就不停的彈出棧首,直到棧首存活。這一系列操作可以滿足均攤複雜度 \(O(1)\) ,很強,是使用莫隊時搭配的好夥伴。
以上。
程式碼如下:
#include<bits/stdc++.h> using namespace std; const int N=5e5+5,Q=5e5+5; int n,q,a[N]; int bel[N],size; struct Query{int l,r,id;}s[Q]; bool cmp(Query a,Query b) { if(bel[a.l]!=bel[b.l]) return a.l<b.l; if(bel[a.l]&1) return a.r<b.r; return a.r>b.r; } int cnt[N],ans[Q]; int l=1,r=0,res=0; stack<int> st; int alive[N]; int main() { cin>>n; for(int i=1;i<=n;++i) scanf("%d",&a[i]); cin>>q; for(int i=1;i<=q;++i) scanf("%d%d",&s[i].l,&s[i].r),s[i].id=i; size=sqrt(n); for(int i=1,cnt=0;i<=n;i+=size,++cnt) { for(int j=i;j<=n&&j<i+size;++j) bel[j]=cnt; } sort(s+1,s+1+q,cmp); for(int i=1;i<=q;++i) { while(r<s[i].r) { r++; if(cnt[a[r]]==1) --res,alive[a[r]]^=1; cnt[a[r]]++; if(cnt[a[r]]==1) ++res,alive[a[r]]^=1,st.push(a[r]); } while(r>s[i].r) { if(cnt[a[r]]==1) --res,alive[a[r]]^=1; cnt[a[r]]--; if(cnt[a[r]]==1) ++res,alive[a[r]]^=1,st.push(a[r]); r--; } while(l<s[i].l) { if(cnt[a[l]]==1) --res,alive[a[l]]^=1; cnt[a[l]]--; if(cnt[a[l]]==1) ++res,alive[a[l]]^=1,st.push(a[l]); l++; } while(l>s[i].l) { l--; if(cnt[a[l]]==1) --res,alive[a[l]]^=1; cnt[a[l]]++; if(cnt[a[l]]==1) ++res,alive[a[l]]^=1,st.push(a[l]); } while(!st.empty()&&!alive[st.top()]) st.pop(); if(st.empty()) ans[s[i].id]=0; else ans[s[i].id]=st.top(); } for(int i=1;i<=q;++i) printf("%d\n",ans[i]); return 0; }