The Little Elephant loves playing with arrays. He has array a, consisting of n positive integers, indexed from 1 to n. Let's denote the number with index i as ai.
Additionally the Little Elephant has m queries to the array, each query is characterised by a pair of integers lj and rj (1 ≤ lj ≤ rj ≤ n). For each query lj, rj the Little Elephant has to count, how many numbers x exist, such that number x occurs exactly x times among numbersalj, alj + 1, ..., arj.
Help the Little Elephant to count the answers to all queries.
The first line contains two space-separated integers n and m (1 ≤ n, m ≤ 105) — the size of array a and the number of queries to it. The next line contains n space-separated positive integers a1, a2, ..., an (1 ≤ ai ≤ 109). Next m lines contain descriptions of queries, one per line. The j-th of these lines contains the description of the j-th query as two space-separated integers lj and rj (1 ≤ lj ≤ rj ≤ n).
In m lines print m integers — the answers to the queries. The j-th line should contain the answer to the j-th query.
7 2 3 1 2 2 3 3 7 1 7 3 4
31
这题可以用离线处理,先读入所有的数据,然后保存所有的终点,并按从小到大排序。我采用的是区间更新,单点查询的方法,对于每一个价值value,记录它的个数cnt[value]以及出现的每一个位置pos[value],考虑到开数组可能要很大的内存(10^5)*(10^5),所以用vector<int>pos[maxn]来表示,因为实际上数据输入的内存要远远小于(10^5)*(10^5)。
从小遍历这n个数,更新cnt[]和pos[],如果出现cnt[value]==value,说明以当前点为终点,起点在1~pos[value][0]都符合,所以这段区间的点都要加1,并开一个结构体pre,记录这一段区间;如果出现cnt[value]>value的时候,说明前一段记录的区间上的点已经不能成立cnt[value]==value,所以该区间都减1,然后新的区间pos[value][pre[value].id-1]+1~pos[value][pre[value].id]都加1,最后查询点就行了。
代码一:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; #define maxn 100060 vector<int>pos[maxn]; int c[maxn],a[maxn],zd[maxn],cnt[maxn],res[maxn]; struct edge{ int l,r,id; }pre[maxn]; struct edge1{ int st,ed,id; }q[maxn]; struct node{ int l,r,num,cnt; }b[4*maxn]; bool cmp(edge1 a,edge1 b){ return a.ed<b.ed; } bool cmp1(edge1 a,edge1 b){ return a.id<b.id; } void build(int l,int r,int i) { int mid; b[i].l=l;b[i].r=r;b[i].cnt=0; if(l==r){ b[i].num=0;return; } mid=(l+r)/2; build(l,mid,i*2); build(mid+1,r,i*2+1); } void update(int l,int r,int num,int i) { int mid; if(b[i].l==l && b[i].r==r){ b[i].cnt+=num;return; } if(b[i].cnt){ b[i*2].cnt+=b[i].cnt; b[i*2+1].cnt+=b[i].cnt; b[i].cnt=0; } mid=(b[i].l+b[i].r)/2; if(r<=mid)update(l,r,num,i*2); else if(l>mid)update(l,r,num,i*2+1); else{ update(l,mid,num,i*2); update(mid+1,r,num,i*2+1); } } int question(int id,int i) { int mid; if(b[i].l==id && b[i].r==id){ b[i].num+=b[i].cnt; b[i].cnt=0; return b[i].num; } if(b[i].cnt){ b[i*2].cnt+=b[i].cnt; b[i*2+1].cnt+=b[i].cnt; b[i].cnt=0; } mid=(b[i].l+b[i].r)/2; if(id<=mid)return question(id,i*2); else return question(id,i*2+1); } int main() { int n,m,i,j,t,l,r,ind,value; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++){ scanf("%d",&a[i]); } for(i=1;i<=m;i++){ scanf("%d%d",&q[i].st,&q[i].ed); q[i].id=i; } sort(q+1,q+1+m,cmp); memset(cnt,0,sizeof(cnt)); for(i=1;i<=n;i++){ pos[i].clear(); } build(1,n,1); ind=1; for(i=1;i<=n;i++){ value=a[i]; if(value<=n){ cnt[value]++; pos[value].push_back(i); if(cnt[value]==value){ pre[value].l=1;pre[value].r=pos[value][0];pre[value].id=0; update(pre[value].l,pre[value].r,1,1); } else if(cnt[value]>value){ update(pre[value].l,pre[value].r,-1,1); pre[value].id++; pre[value].l=pos[value][pre[value].id-1]+1; pre[value].r=pos[value][pre[value].id]; update(pre[value].l,pre[value].r,1,1); } while(q[ind].ed==i && ind<=m){ res[q[ind].id]=question(q[ind].st,1); ind++; } } } sort(q+1,q+1+m,cmp1); for(i=1;i<=m;i++){ if(i==m)printf("%d\n",res[i]); else printf("%d ",res[i]); } } return 0; }
代码二:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<string> #include<algorithm> using namespace std; typedef long long ll; #define inf 0x7fffffff #define maxn 100060 #define pi acos(-1.0) int num[maxn],pre[maxn],a[maxn]; int cnt; struct node{ int x,y,idx; }ques[maxn]; int ans[maxn]; struct node1{ int l,r,num; }b[4*maxn]; vector<int>pos[maxn]; vector<int>::iterator p; bool cmp(node a,node b){ return a.y<b.y; } void build(int l,int r,int i) { int mid; b[i].l=l;b[i].r=r;b[i].num=0; if(l==r)return; mid=(l+r)/2; build(l,mid,i*2); build(mid+1,r,i*2+1); } void update(int l,int r,int num,int i) { int mid; if(b[i].l==l && b[i].r==r){ b[i].num+=num; return; } mid=(b[i].l+b[i].r)/2; if(r<=mid)update(l,r,num,i*2); else if(l>mid)update(l,r,num,i*2+1); else{ update(l,mid,num,i*2); update(mid+1,r,num,i*2+1); } } void question(int idx,int i) { int mid; if(b[i].l==idx && b[i].r==idx){ cnt+=b[i].num; return; } cnt+=b[i].num; mid=(b[i].l+b[i].r)/2; if(idx<=mid)question(idx,i*2); else question(idx,i*2+1); } int main() { int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++){ scanf("%d",&a[i]); } for(i=1;i<=m;i++){ scanf("%d%d",&ques[i].x,&ques[i].y); ques[i].idx=i; } build(1,100000,1); sort(ques+1,ques+1+m,cmp); memset(ans,0,sizeof(ans)); memset(num,0,sizeof(num)); for(i=1;i<=100000;i++){ pre[i]=1; pos[i].clear(); } int wei=1; int pre1=1,pre2; int flag=1; for(i=1;i<=n;i++){ //printf("---->%d\n",i); if(a[i]<=100000){ if(a[i]==1){ if(flag){ flag=0; update(1,i,1,1); pre2=i; } else{ update(pre1,pre2,-1,1); pre1=pre2+1; pre2=i; update(pre1,pre2,1,1); } } else{ num[a[i] ]++; if(num[a[i] ]==a[i] ){ p=pos[a[i] ].begin(); update(pre[a[i] ],*p,1,1); pos[a[i] ].push_back(i); } else if(num[a[i] ]==a[i]+1){ p=pos[a[i] ].begin(); update(pre[a[i] ],*p,-1,1); pre[a[i] ]=*p+1; update(pre[a[i] ],i,1,1); pos[a[i] ].erase(p); pos[a[i] ].push_back(i); num[a[i] ]--; } else{ pos[a[i] ].push_back(i); } } } while(ques[wei].y==i && wei<=m){ int l=ques[wei].x; cnt=0; question(l,1); ans[ques[wei].idx ]=cnt; wei++; } } cnt=0; question(1,1); for(i=1;i<=m;i++){ printf("%d\n",ans[i]); } } return 0; }