CF940F Machine Learning

CF940F(带修莫队)

CF940F

题目要求很简单,支持单点修改和区间查询出现次数的 \(\text{mex}\) ,单点修改很简单,但是 \(\text{mex}\) 的查询成为了一个棘手的问题。

考虑使用带修莫队,将所有操作离线,那么修改操作可以通过第三维的 \(t\) 实现,但现在的问题是如何更新信息并查询出现次数的 \(\text{mex}\)

每个数的出现次数(记作 \(cnt\) )很好维护,可以在 \(\text O(1)\) 的时间内转移,而出现次数的出现次数(记作 \(cntcnt\))也可以同时 \(\text O(1)\) 转移。现在需要考虑如何根据这些信息来求解出现次数的 \(\text{mex}\)

对于一个维护好信息的区间,只需要在当前区间的 \(cntcnt\) 中直接进行暴力查询,找到第一个为 \(0\) 的位置就是答案,由于 \(\text{mex}\) 的最大值就是 \(\sqrt{n}\) ,因此暴力查询的总时间复杂度为 \(\text O(n\sqrt{n})\) ,而带修莫队时间复杂度为 \(\text O(n^{\frac{5}{3}})\) ,因此对总时间复杂度没有影响。

另外一个需要注意的点是,该题 \(a_i\) 的数据规模为 \([1,10^9]\) ,而 \(n\)\(q\) 的规模为 \([1,10^5]\) ,而我们又要使用桶来统计,因此在读入时需要对 \(a_i\)\(2\) 操作的 \(x\) 进行离散化,因此离散数组的大小应为 \(2\text{e}5\)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<limits.h>
#include<cmath>
#define mem(a,b) memset(a,b,sizeof(a));
using namespace std;
template<typename T> void read(T &k)
{
 	k=0;
	T flag=1;char b=getchar();
	while (b<'0' || b>'9') {flag=(b=='-')?-1:1;b=getchar();}
	while (b>='0' && b<='9') {k=(k<<3)+(k<<1)+(b^48);b=getchar();}
	k*=flag;
}
const int _SIZE=1e5;
int n,q,len;
struct QUERY{
	int l,r,t,id;
}que[_SIZE+5],mod[_SIZE+5];
bool cmp(QUERY x,QUERY y)
{
	if (x.l/len!=y.l/len) return x.l<y.l;
	if (x.r/len!=y.r/len) return x.r<y.r;
	return x.t<y.t;
}
int cntq,cntm;
int val[(_SIZE<<1)+5],a[_SIZE+5],tot;
int cnt[(_SIZE<<2)+5],cntcnt[(_SIZE<<2)+5];
int ans[_SIZE+5];
int tail;
void add(int x)
{
	cntcnt[cnt[x]++]--;
	cntcnt[cnt[x]]++;
}
void del(int x)
{
	cntcnt[cnt[x]--]--;
	cntcnt[cnt[x]]++;
}
void update(int x,int t)
{
	if (que[x].l<=mod[t].l && mod[t].l<=que[x].r)
	{
		del(a[mod[t].l]);
		add(mod[t].r);
	}
	swap(a[mod[t].l],mod[t].r);
}
int main()
{
	read(n),read(q);
	len=pow(n,0.666);
	for (int i=1;i<=n;i++)
	{
		read(a[i]);val[++tail]=a[i];
	}
	
	for (int i=1;i<=q;i++)
	{
		int t,x,y;
		read(t);read(x);read(y);
		if (t==1)
		{
			cntq++,
			que[cntq].id=cntq,que[cntq].l=x,
			que[cntq].r=y,que[cntq].t=cntm;
		}
		else
		{
			cntm++,
			mod[cntm].l=x,mod[cntm].r=y,val[++tail]=y;
		}
	}
	
	sort(val+1,val+tail+1);
	tot=unique(val+1,val+tail+1)-val;
	for (int i=1;i<=n;i++)
		a[i]=lower_bound(val+1,val+tot+1,a[i])-val-1;
	for (int i=1;i<=cntm;i++)
		mod[i].r=lower_bound(val+1,val+tot+1,mod[i].r)-val-1;
	
	sort(que+1,que+cntq+1,cmp);
	int lcur=1,rcur=0,tcur=0;
	for (int i=1;i<=cntq;i++)
	{
		while (lcur>que[i].l) add(a[--lcur]);
		while (rcur<que[i].r) add(a[++rcur]);
		while (lcur<que[i].l) del(a[lcur++]);
		while (rcur>que[i].r) del(a[rcur--]);
		while (tcur<que[i].t) update(i,++tcur);
		while (tcur>que[i].t) update(i,tcur--);
		//printf("i=%d %d~%d:",que[i].id,que[i].l,que[i].r);for (int j=1;j<=tot;j++) printf("%d ",cntcnt[j]); puts("");
		for (ans[que[i].id]=1;cntcnt[ans[que[i].id]]>0;ans[que[i].id]++);
	}
	for (int i=1;i<=cntq;i++) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2022-07-06 10:39  Hanx16Msgr  阅读(31)  评论(0编辑  收藏  举报