1. 程式人生 > 實用技巧 >題解 CF1000F 【One Occurrence】

題解 CF1000F 【One Occurrence】

本題解用於記錄一下一個優秀的東西——懶標記

題解

可以很輕易的想到莫隊的做法,但是題目讓你輸出的是滿足條件的一個數,而不是滿足條件的數的個數,似乎很難去 \(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;
}