B题和那个多校比赛的一个题目有点像,大意都是求一段序列的满足某个元素出现次数为一个固定值的个数,都差不多
我用的线段树实现的,写的太龊了
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=100010;
vector<int> g[maxn];
int d[maxn<<2],a[maxn],b[maxn],ans[maxn];
struct Node
{
int l,r,id;
}q[maxn];
void update(int p,int val,int l,int r,int rt)
{
if(l==r) { d[rt]=val;return; }
int m=(l+r)>>1;
if(p<=m) update(p,val,lson);
else update(p,val,rson);
d[rt]=d[rt<<1]+d[rt<<1|1];
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r) return d[rt];
int m=(l+r)>>1,ret1=0,ret2=0;
if(L<=m) ret1=query(L,R,lson);
if(R>m) ret2=query(L,R,rson);
return ret1+ret2;
}
int cmp(Node a,Node b)
{
return a.r < b.r;
}
int bin(int key,int l,int r)
{
while(l<=r)
{
int m=(l+r)>>1;
if(b[m]==key) return m;
else if(b[m]>key) r=m-1;
else l=m+1;
}
}
int main()
{
int n,m,l,r;
while(scanf("%d%d",&n,&m)==2)
{
for(int i=0;i<n;i++) scanf("%d",&a[i]),b[i]=a[i],g[i].clear();
memset(d,0,sizeof(d));
sort(b,b+n);
int k=unique(b,b+n)-b;
for(int i=0;i<m;i++)
{
scanf("%d%d",&l,&r);
q[i].l=l-1,q[i].r=r-1;
q[i].id=i;
}
sort(q,q+m,cmp);
int cnt=0;
for(int i=0;i<n;i++)
{
int p=bin(a[i],0,k-1);
if(g[p].size()<a[i]-1){
g[p].push_back(i);
}else{
g[p].push_back(i);
int sz=g[p].size();
update(g[p][sz-a[i]],1,0,n-1,1);
if(sz>=a[i]+1) update(g[p][sz-a[i]-1],-1,0,n-1,1);
if(sz>=a[i]+2) update(g[p][sz-a[i]-2],0,0,n-1,1);
}
while(cnt<m&&q[cnt].r==i){
ans[q[cnt].id]=query(q[cnt].l,q[cnt].r,0,n-1,1);
cnt++;
}
if(cnt==m) break;
}
for(int i=0;i<m;i++) printf("%d\n",ans[i]);
}
return 0;
}
不过这种方法要比线段树慢很多
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100010;
int chd[500][maxn],a[maxn],b[maxn],t[maxn];
int main()
{
int n,m,l,r;
while(scanf("%d%d",&n,&m)==2)
{
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
if(t[i]<=n) a[t[i]]++;
}
int tot=0;
for(int i=1;i<=n;i++)
if(a[i]>=i){
b[tot]=i;
for(int j=1;j<=n;j++) chd[tot][j]=chd[tot][j-1]+(t[j]==i);
tot++;
}
while(m--){
scanf("%d%d",&l,&r);
int ans=0;
for(int i=0;i<tot;i++)
if(chd[i][r]-chd[i][l-1]==b[i]) ans++;
printf("%d\n",ans);
}
}
return 0;
}