Codeforces Round #466 (Div. 2) F - Machine Learning 带修改莫队



题意:

令 ci 表示 区间 [l,r] 中数字 i 的出现次数

每个询问求区间 [l,r] 中 Mex{ci}

要求支持单点权值修改

这个题一看就很不好维护

果断想到莫队 之后意识到 Mex 这个操作也不好搞

可以用个 log 数据结构维护一下 但是复杂度就过不去了

这时注意到 由等差数列求和公式

每一个询问的 result <2*sqrt*(n)

所以每次暴力转移 暴力枚举答案 复杂度正确


codeforces的题解写的真良心

要是学带修改莫队算法 直接翻译下这个就行了



#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=200100;

int block,bel[N>>1];

struct Query
{
	int t,l,r,pos;
	// t : the number of change queries before
	friend bool operator <(const Query &x,const Query &y)
	{return bel[x.t]==bel[y.t] ? (bel[x.l]==bel[y.l] ? x.r<y.r : bel[x.l]<bel[y.l]) : bel[x.t]<bel[y.t];}
	
}q[N>>1];

int P[N>>1],X[N>>1],Y[N>>1];
int pre[N>>1],a[N>>1],st[N],top;

inline int get_hash(int x)
{
	int l(1),r(top),mid;
	while(l<=r)
	{
		mid=l+r>>1;
		st[mid]<=x ? l=mid+1 : r=mid-1 ;
	}
	return l-1;
}

int tot;

int c[N],size[N];

inline void modify(int x,int val)
{size[c[x]]--;c[x]+=val;size[c[x]]++;}

inline int query()
{int res(1);while(size[res])res++;return res;}

int ans[N>>1];

void modui()
{
	register int i,l(1),r(0),t(0);
	for(i=1;i<=tot;++i)
	{
		while(t<q[i].t)
			if(P[t+1]<=r && P[t+1]>=l)
				t++,modify(Y[t],-1),modify(X[t],1),a[P[t]]=X[t];
			else t++,a[P[t]]=X[t];
		while(t>q[i].t)
			if(P[t]<=r && P[t]>=l)
				modify(X[t],-1),modify(Y[t],1),a[P[t]]=Y[t],t--;
			else a[P[t]]=Y[t],t--;
		while(r<q[i].r) r++,modify(a[r],1);
		while(l>q[i].l) l--,modify(a[l],1);
		while(r>q[i].r) modify(a[r],-1),r--;
		while(l<q[i].l) modify(a[l],-1),l++;
		ans[q[i].pos]=query();
	}
}

int main()
{
	int n=read(),Q=read();
	
	register int i(1),j,opt,now,tmp(1);
	
	while(i*i*i<n) i++;
	block=i*i;
	for(i=j=now=1;i<=n;++i,++j)
	{
		bel[i]=now;
		if(j==block) now++,j=0;
	}
	
	for(i=1;i<=n;++i) a[i]=read();
	memcpy(pre,a,sizeof(int)*(n+1));
	for(i=1,now=0;i<=Q;++i)
	{
		opt=read();
		switch(opt)
		{
			case 1:
				q[++tot].t=now;q[tot].pos=tot;
				q[tot].l=read();q[tot].r=read();
				break;
			case 2:
				P[++now]=read();
				Y[now]=pre[P[now]];
				pre[P[now]]=X[now]=read();
				break;
		}
	}
	sort(q+1,q+1+tot);
	
	top=n+now;
	memcpy(st,a,sizeof(int)*(n+1));
	memcpy(st+n+1,X+1,sizeof(int)*now);
	sort(st+1,st+1+top);
	for(i=2;i<=top;++i)
		if(st[i]!=st[i-1])
			st[++tmp]=st[i];
	top=tmp;
	for(i=1;i<=n;++i) a[i]=get_hash(a[i]);
	for(i=1;i<=now;++i) X[i]=get_hash(X[i]),Y[i]=get_hash(Y[i]);
	
	modui();
	
	for(i=1;i<=tot;++i)
		print(ans[i]),puts("");
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值