P7764 COCI2016-2017 5 Poklon

题目描述

给定一个包含 \(N\) 个自然数的数组。

接着需要回答 \(Q\) 次询问,每次询问输出区间 \([L,R]\) 内恰好出现两次的自然数的数量。

输入格式

第一行,两个整数 \(N,Q\),分别表示数组元素数量和询问次数。

第二行,\(N\) 个整数,表示数组中的元素。

接下来的 \(Q\) 行,每行两个整数 \(L,R\),表示询问的区间。

输出格式

\(Q\) 行,依次对应每次询问的结果。

样例 #1

样例输入 #1

5 1
1 2 1 1 1
1 3

样例输出 #1

1

样例 #2

样例输入 #2

5 2
1 1 1 1 1
2 4
2 3

样例输出 #2

0
1

样例 #3

样例输入 #3

5 2
1 1 2 2 3
1 1
1 5

样例输出 #3

0
2

提示

【样例 1 解释】

区间 \([1,3]\) 中只有 \(1\) 恰好出现了两次。

【数据规模与约定】

对于 \(40\%\) 的数据,\(N,Q \le 5000\)

对于 \(100\%\) 的数据,\(1 \le N,Q \le 5 \times 10^5\)\(1 \le L \le R \le N\),数组中的元素都是小于 \(10^9\) 的自然数。

【提示与说明】

题目译自 COCI 2016-2017 CONTEST #5 T5 Poklon

本题分值按 COCI 原题设置,满分 \(140\)

分析

离散化之后就是莫队板子

#include<bits/stdc++.h>
using namespace std;
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<<1)+(x<<3)+(c&15),c=getchar();
	return x*f;
}
struct node{
	int l,r,id;
}q[500005];
int n,m,a[500005],bl,cnt[500005],pos[500005],t[500005],ans[500005],tcnt,res,vis[500005];
bool cmp(node x,node y){return pos[x.l]^pos[y.l]?pos[x.l]<pos[y.l]:(pos[x.l]&1?x.r<y.r:x.r>y.r);}
void add(int x){
	++cnt[x];
	if(cnt[x]>2&&vis[x])vis[x]=0,--res;
	if(cnt[x]==2)vis[x]=1,++res;
}
void del(int x){
	--cnt[x];
	if(cnt[x]<2&&vis[x])vis[x]=0,--res;
	if(cnt[x]==2)vis[x]=1,++res;
}
int main(){
	n=read(),m=read();bl=pow(n,0.666);
	for(int i=1;i<=n;i++)a[i]=read(),pos[i]=(i-1)/bl+1,t[++tcnt]=a[i];
	for(int i=1;i<=m;i++)q[i].l=read(),q[i].r=read(),q[i].id=i;
	sort(t+1,t+tcnt+1);
	tcnt=unique(t+1,t+tcnt+1)-t-1;
	for(int i=1;i<=n;i++)a[i]=lower_bound(t+1,t+tcnt+1,a[i])-t;
	sort(q+1,q+m+1,cmp);
	for(int i=1,l=1,r=0;i<=m;i++){	
		while(q[i].l<l)add(a[--l]);
		while(q[i].l>l)del(a[l++]);
		while(q[i].r>r)add(a[++r]);
		while(q[i].r<r)del(a[r--]);
		ans[q[i].id]=res;
	}
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}
posted @ 2023-06-24 14:17  alex_liu09  阅读(36)  评论(0)    收藏  举报