(CodeForces - 940F)Machine Learning(带修莫队+离散化)

题目链接:Problem - 940F - Codeforces

题意:

 一看是一个离散的区间查询带修改问题就知道可以用带修莫队来解决。

我们开一个cnt数组记录当前值出现的次数,再记录一个count数组来记录出现次数相同的值出现的次数(听起来有些绕哈,结合题意思考一下就知道是什么意思了),下面就是正常的带修莫队了,对于求mex我们是用暴力求得的。仔细观察一下数据范围,发现需要用到离散化,其他就是一个正常的带修莫队了,下面上代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<vector>
using namespace std;
const int N=1e6+10;
int a[N],sum[N],cnt[N],Count[N],clock[N];
struct node{
	int l,r,t,id;
}p[N];
//带修莫队中左右区间都要分块
bool cmp(node a,node b)
{
	if(clock[a.l]!=clock[b.l]) return clock[a.l]<clock[b.l];
	if(clock[a.r]!=clock[b.r]) return clock[a.r]<clock[b.r];
	return a.t<b.t;
}
struct Node{
	int pos,val;
}q[N];
map<int,int>mp;
void add(int x)
{
	Count[cnt[x]]--;
	cnt[x]++;
	Count[cnt[x]]++;
}
void sub(int x)
{
	Count[cnt[x]]--;
	cnt[x]--;
	Count[cnt[x]]++;
}
void change(int i,int j)
{
	if(p[i].l<=q[j].pos&&q[j].pos<=p[i].r)
	{
		sub(a[q[j].pos]);
		add(q[j].val);
	}
	swap(a[q[j].pos],q[j].val);
}
//离散化数组 
vector<int>alls;
//离散化函数 
int find(int x)
{
	return lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1;
}
int main()
{
	int n,m;
	cin>>n>>m;
	int pl=max(1,(int)pow(n,2.0/3.0));
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		alls.push_back(a[i]);//将数组初始值加入待离散化数组 
		clock[i]=(i-1)/pl+1;
	}
	int cntq=0,cntc=0,op,x,y;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&op,&x,&y);
		if(op==1)
		{
			cntq++;
			p[cntq].l=x;
			p[cntq].r=y;
			p[cntq].t=cntc;
			p[cntq].id=cntq;
		}
		else
		{
			cntc++;
			q[cntc].pos=x;
			q[cntc].val=y;
			alls.push_back(y);//将修改后的值也加入待离散化数组
		}
	}
	//离散化 
	sort(alls.begin(),alls.end());
	alls.erase(unique(alls.begin(),alls.end()),alls.end());
	for(int i=1;i<=n;i++)//将原数组的值变为其离散化后的值,防止数组存不下 
		a[i]=find(a[i]);
	for(int i=1;i<=cntc;i++)//将修改后的值变为其离散化后的值,防止数组存不下
		q[i].val=find(q[i].val);
	sort(p+1,p+cntq+1,cmp);
	int l=1,r=0,t=0;
	for(int i=1;i<=cntq;i++)
	{
		while(l<p[i].l) sub(a[l++]);
		while(l>p[i].l) add(a[--l]);
		while(r<p[i].r) add(a[++r]);
		while(r>p[i].r) sub(a[r--]);
		while(t<p[i].t) change(i,++t);
		while(t>p[i].t) change(i,t--);
		int ans=1;
		while(Count[ans]) ans++;//暴力求得目标区间的mex 
		sum[p[i].id]=ans;
	}
	for(int i=1;i<=cntq;i++)
		printf("%d\n",sum[i]);
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值