CF1000F One Occurrence

题意

给定一个长度为\(n\)的序列和\(m\)个询问,每次询问给出\(l\)\(r\),输出\([l,r]\)内只出现一次的某个数字,若没有则输出\(0\)\(n,m<=5*10^5\)

思路

一眼莫队,然而刚开始为了维护中出现一次的数字集合使用了\(set\)或者\(vector\)都会在第\(8\)个测试点上卡死,在值域上直接枚举则会在第\(70\)个测试点上寄掉(???)。

颓了一眼题解发现了值域上分块的做法,受益匪浅。

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1000050;
int n,m,K,a[maxn],ed[maxn],bel[maxn],st[maxn];
int ans[maxn],col[maxn],cnt,maxx=-1,minn=2147483640;
int sum[10000];
struct ques{
	int l,r,id;
	bool operator<(const ques &x)const{
		if(bel[l]!=bel[x.l]) return l<x.l;
		if(bel[l]&1) return r<x.r;
		return r>x.r;
	}
}q[maxn]; 
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=(s<<1)+(s<<3)+(ch^48);
		ch=getchar();
	}
	return s*w;
}
inline void pre(){
	int sq=sqrt(500000);
	for(int i=1;i<=sq;++i){
		st[i]=n/sq*(i-1)+1;
		ed[i]=n/sq*i;
	}
	ed[sq]=500000;
	for(int i=1;i<=sq;++i){
		for(int j=st[i];j<=ed[i];++j) bel[j]=i;
	}
	return;		
}
inline void add(int k){
	if(col[k]==0) cnt++,sum[bel[k]]++;
	col[k]++;
	if(col[k]==2) cnt--,sum[bel[k]]--;
	return;
}
inline void del(int k){
	if(col[k]==2) cnt++,sum[bel[k]]++;
	col[k]--;
	if(col[k]==0) cnt--,sum[bel[k]]--;
	return;
}
inline int finds(){
	for(int i=bel[500000];i>=1;--i){
		if(!sum[i]) continue;
		for(int j=ed[i];j>=st[i];j--) if(col[j]==1) return j;
	}
	return 0;
}
void solve(){
		sort(q+1,q+1+m);
		for(int i=1,l=1,r=0;i<=m;++i){
			while(l>q[i].l) add(a[--l]);
			while(r<q[i].r) add(a[++r]);
			while(l<q[i].l) del(a[l++]);
			while(r>q[i].r) del(a[r--]);
			if(cnt) ans[q[i].id]=finds(); 
			else ans[q[i].id]=0;
		}
}
int main(){
	n=read();pre();
	for(int i=1;i<=n;++i) a[i]=read();
	m=read();
	for(int i=1;i<=m;++i){
		q[i].l=read();q[i].r=read();q[i].id=i;
	}
	solve();
	for(int i=1;i<=m;++i) printf("%d\n",ans[i]);
	return 0;
}
/*
5
1 1 2 1 1
10
2 1 3
1 1
2
*/
posted @ 2022-06-29 18:41  Broken_Eclipse  阅读(21)  评论(0编辑  收藏  举报

Loading