Little Elephant and Array(扫描线+树状数组)
题目
题目链接
题目大意
给出一个长度为n的序列,进行m次询问。
每次询问区间[ l ,r ]内,有多少个数字x刚好出现了x次。
题目思路
1.这个题是可以用莫队做的

#include<iostream> #include<algorithm> #include<map> #include<math.h> using namespace std; const int maxn=1e6+100; int a[maxn],b[maxn],c[maxn]; int belong[maxn],res[maxn]; struct node{ int l,r,id; }q[maxn]; int ans=0; int mp[maxn]; int cnt=0; bool cmp(node x,node y){ if(belong[x.l]!=belong[y.l]){ return x.l<y.l; } else{ if(belong[x.l]&1){ return x.r<y.r; } else{ return x.r>y.r; } } } void add(int pos){ if(mp[a[pos]]==c[pos]){ ans--; } mp[a[pos]]++; if(mp[a[pos]]==c[pos]){ ans++; } } void remove(int pos){ if(mp[a[pos]]==c[pos]){ ans--; } mp[a[pos]]--; if(mp[a[pos]]==c[pos]){ ans++; } } int main(){ int n,m; cin>>n>>m; int block=(int)sqrt(n); for(int i=1;i<=n;i++){ cin>>a[i]; b[i]=c[i]=a[i]; belong[i]=(i-1)/block+1; } sort(b+1,b+n+1); for(int i=1;i<=n;i++){ a[i]=lower_bound(b+1,b+n+1,a[i])-b; } for(int i=1;i<=m;i++){ cin>>q[i].l>>q[i].r; q[i].id=i; } sort(q+1,q+m+1,cmp); for(int l=1,r=0,i=1;i<=m;i++){ int ql=q[i].l,qr=q[i].r; while(l<ql){ remove(l++); } while(l>ql){ add(--l); } while(r>qr){ remove(r--); } while(r<qr){ add(++r); } res[q[i].id]=ans; } for(int i=1;i<=m;i++){ cout<<res[i]<<endl; } }
2.扫描线+树状数组
首先呢我们可以把[li,ri]给离线出来,假如询问是[li,ri]的然后我们可以用一个vector给它存起来,就是把ri存起来就是v[y].push({x,id}),这里相当于降维,然后从前向后扫描数组
对于每一个y,求出来[1,r]的区间里的全部贡献,转化为res[x.second] = query(i)-query(x.first-1);,
对于这个题
所以以区间[ 2 , 2 , 2 , 2 ] 为例:
1.r = 1 ,左端点的贡献分别为:[ 0 , 0 , 0 , 0 ]
2. r = 2 ,左端点的贡献分别为:[ 1 , 0 , 0 , 0 ] 这里r=2你只需要ri=2,然后li是小于等与2的,这样区间【1,2】和就是1
3. r = 3 ,左端点的贡献分别为:[ − 1 , 1 , 0 , 0 ] 这里r=3,你只需要看ri=3,li可以是【1,2,3】看看如果是1,前缀和就是0。如果是2,前缀和就是1。如果是3就是0
4. r = 4 ,左端点的贡献分别为:[ 0 , − 1 , 1 , 0 ] 这个和上一个一样分析,然后找出这个数组的变化规律来
记住你看i的时候一定要记得一个点是固定的就是这个ri,然后再看[1.ri]的影响,从而改变数组

#include<iostream> #include<algorithm> #include<set> #include<vector> #include<bits/stdc++.h> using namespace std; const int maxn=1e6+100; typedef long long ll; typedef pair<int,int>PII; int a[maxn]; int c[maxn]; int n,m; int lowbit(int x){ return x&-x; } void add(int x,int val){ for(int i=x;i<=n;i+=lowbit(i)){ c[i]+=val; } } ll query(int x){ int ans=0; for(int i=x;i>0;i-=lowbit(i)){ ans+=c[i]; } return ans; } vector<PII>q[maxn]; ll ans[maxn]; multiset<int>s[maxn]; int main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; } int x,y; for(int i=1;i<=m;i++){ cin>>x>>y; if(x>y){ swap(x,y); } q[y].push_back({x,i}); } for(int i=1;i<=n;i++){ if(a[i]<=n){ s[a[i]].insert(i); int sz=s[a[i]].size(); if(sz==a[i]){ int sp=*s[a[i]].begin(); add(sp,1); } else if(sz==a[i]+1){ int sp=*s[a[i]].begin(),tp=*next(s[a[i]].begin()); add(sp,-2); add(tp,1); } else if(sz==a[i]+2){ int sp=*s[a[i]].begin(),tp=*next(s[a[i]].begin()),tpp=*next(next(s[a[i]].begin())); add(sp,1); add(tp,-2); add(tpp,1); s[a[i]].erase(sp); } } for(auto x:q[i]){ ans[x.second]=query(i)-query(x.first-1); } } for(int i=1;i<=m;i++){ printf("%lld\n",ans[i]); } return 0; }