【CF220B】Little Elephant and Array

题目

题目链接:https://codeforces.com/problemset/problem/220/B
小象喜欢和数组玩。现在有一个数组 \(a\),含有 \(n\) 个正整数,记第 \(i\) 个数为 \(A_i\)

现在有 \(m\) 个询问,每个询问包含两个正整数 \(l_j\)\(r_j(1\leq l_j \leq r_j \leq n)\),小象想知道在 \(A_{l_j}\)\(A_{r_j}\) 之中有多少个数 \(x\),其出现次数也为 \(x\)

思路

询问按 \(r\) 从小到大离线,然后双指针扫描询问和 \(A\)
当扫到的数字是 \(x\) 时,如果前面已经有 \(k\)\(x\) 出现(\(k\geq x-1\)),那么如果此时 \(r=x\)\(l\) 在第 \(x-k\)\(x-k+1\)\(x\) 之间是可以被 \(x\) 贡献的。同时需要减去上一次 \(x\) 的贡献。
问题转化为区间加单点求和,线段树即可。
时间复杂度 \(O(m\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N=100010;
int n,Q,a[N],ans[N];
vector<int> pos[N]; 

struct Query
{
	int l,r,id;
}ask[N];

bool cmp(Query x,Query y)
{
	return x.r<y.r;
}

int read()
{
	int d=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

struct SegTree
{
	int cnt[N*4];
	
	void pushdown(int x)
	{
		if (cnt[x])
		{
			cnt[x*2]+=cnt[x];
			cnt[x*2+1]+=cnt[x];
			cnt[x]=0;
		}
	}
	
	void update(int x,int l,int r,int ql,int qr,int v)
	{
		if (l==ql && r==qr)
		{
			cnt[x]+=v;
			return;
		}
		pushdown(x);
		int mid=(l+r)>>1;
		if (qr<=mid) update(x*2,l,mid,ql,qr,v);
		else if (ql>mid) update(x*2+1,mid+1,r,ql,qr,v);
		else update(x*2,l,mid,ql,mid,v),update(x*2+1,mid+1,r,mid+1,qr,v);
	}
	
	int query(int x,int l,int r,int k)
	{
		if (l==k && r==k) return cnt[x];
		pushdown(x);
		int mid=(l+r)>>1;
		if (k<=mid) return query(x*2,l,mid,k);
			else return query(x*2+1,mid+1,r,k);
	}
}seg;

int main()
{
	n=read(); Q=read();
	for (int i=1;i<=n;i++)
	{
		a[i]=read();
		pos[i].push_back(0);
	}
	for (int i=1;i<=Q;i++)
	{
		ask[i].l=read(); ask[i].r=read();
		ask[i].id=i;
	}
	sort(ask+1,ask+1+Q,cmp);
	for (int i=1,j=1;i<=Q;i++)
	{
		for (;j<=ask[i].r;j++)
		{
			if (a[j]>n) continue;
			pos[a[j]].push_back(j);
			int k=pos[a[j]].size();
			if (k>a[j])
			{
				if (k>a[j]+1)
					seg.update(1,1,n+1,pos[a[j]][k-a[j]-2]+2,pos[a[j]][k-a[j]-1]+1,-1);
				seg.update(1,1,n+1,pos[a[j]][k-a[j]-1]+2,pos[a[j]][k-a[j]]+1,1);
			}
		}
		ans[ask[i].id]=seg.query(1,1,n+1,ask[i].l+1);
	}
	for (int i=1;i<=Q;i++)
		printf("%d\n",ans[i]);
	return 0;
}
posted @ 2020-12-03 17:48  stoorz  阅读(78)  评论(0编辑  收藏  举报