题目大意:给定一个序列,多次询问区间内出现两次以上的数的数量
n<=100W 莫队不用想了
考虑对于每个区间的左端点 对这个区间有贡献的数是从这个端点开始所有第二次出现的数
于是我们将区间按照左端点排序 然后从左向右扫
令next[i]为i位置上的数下一次出现的位置
初始将所有第二次出现的数加入树状数组
然后每删除一个点i 将next[i]从树状数组中删除 然后将next[next[i]]加入树状数组
然后处理区间就在树状数组上查询右端点即可
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 1001001 using namespace std; struct query{ int x,y,pos; bool operator < (const query &Y) const { return x < Y.x; } }q[M]; int n,c,m; int a[M],last[M],next[M],ans[M],now=1; bool v[M]; int bit[M]; void Update(int x,int y) { for(;x<=n;x+=x&-x) bit[x]+=y; } int Get_Ans(int x) { int re=0; for(;x;x-=x&-x) re+=bit[x]; return re; } int main() { int i; cin>>n>>c>>m; for(i=1;i<=n;i++) scanf("%d",&a[i]); for(i=1;i<=n;i++) { if(last[a[i]]) next[last[a[i]]]=i; else v[i]=1; last[a[i]]=i; } for(i=1;i<=n;i++) if(v[i]&&next[i]) Update(next[i],1); for(i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].pos=i; sort(q+1,q+m+1); for(i=1;i<=m;i++) { while(now<q[i].x) { if(next[now]) { Update(next[now],-1); if(next[next[now]]) Update(next[next[now]],1); } ++now; } ans[q[i].pos]=Get_Ans(q[i].y); } for(i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
时间: 2024-10-07 10:47:28