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;
}

浙公网安备 33010602011771号