【JZOJ 杂题选讲】CF1209G

题目

在这里插入图片描述

思路

首先如果q=0
那么显然是要把序列分成尽可能多的段,设每段众数的数量为Si,则ans=n-sigma(si)

考虑修改,可以用线段树维护
在这里插入图片描述
然后注意如何维护区间众数即可

代码

#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int maxn=2e5+5;

struct TR{
	int sum,l0,r0,nmin;
};

int n,q,a[maxn],maxa;
set<int> pos[maxn];

int nmax[4*maxn];
void nmax_xg(int k,int l,int r,int x,int z)
{
	if (l==r)
	{
		nmax[k]+=z;
		return;
	}
	int t=k<<1, mid=(l+r)>>1;
	if (x<=mid) nmax_xg(t,l,mid,x,z); else nmax_xg(t+1,mid+1,r,x,z);
	nmax[k]=max(nmax[t],nmax[t+1]);
}
int nmax_cx(int k,int l,int r,int x,int y)
{
	if (x>y) return 0;
	if (x<=l && r<=y) return nmax[k];
	int t=k<<1, mid=(l+r)>>1, re=0;
	if (x<=mid) re=max(re,nmax_cx(t,l,mid,x,y));
	if (mid<y) re=max(re,nmax_cx(t+1,mid+1,r,x,y));
	return re;
}

TR tr[4*maxn];
int bz[4*maxn];
void update(int k,int t)
{
	tr[t].nmin+=bz[k], tr[t+1].nmin+=bz[k];
	bz[t]+=bz[k], bz[t+1]+=bz[k];
	bz[k]=0;
}
TR merge(const TR &a,const TR &b)
{
	if (a.nmin<b.nmin) return a;
		else if (a.nmin>b.nmin) return b;
			else return (TR){a.sum+b.sum+nmax_cx(1,1,n,a.r0+1,b.l0),a.l0,b.r0,a.nmin};
}
void tr_js(int k,int l,int r)
{
	if (l==r)
	{
		tr[k].l0=tr[k].r0=l;
		return;
	}
	int t=k<<1, mid=(l+r)>>1;
	tr_js(t,l,mid), tr_js(t+1,mid+1,r);
	tr[k]=merge(tr[t],tr[t+1]);
}
void tr_xg_sing(int k,int l,int r,int x,int z)
{
	if (l==r)
	{
		nmax_xg(1,1,n,x,z);
		return;
	}
	int t=k<<1, mid=(l+r)>>1;
	update(k,t);
	if (x<=mid) tr_xg_sing(t,l,mid,x,z); else tr_xg_sing(t+1,mid+1,r,x,z);
	tr[k]=merge(tr[t],tr[t+1]);
}
void tr_xg_q(int k,int l,int r,int x,int y,int z)
{
	if (x>y) return;
	if (x<=l && r<=y)
	{
		tr[k].nmin+=z;
		bz[k]+=z;
		return;
	}
	int t=k<<1, mid=(l+r)>>1;
	update(k,t);
	if (x<=mid) tr_xg_q(t,l,mid,x,y,z);
	if (mid<y) tr_xg_q(t+1,mid+1,r,x,y,z);
	tr[k]=merge(tr[t],tr[t+1]);
}

void modify(int x,int sig)
{
	if (pos[x].empty()) return;
	tr_xg_sing(1,0,n,*pos[x].begin(),sig*pos[x].size());
	set<int>::iterator it=pos[x].end();
	it--;
	tr_xg_q(1,0,n,*pos[x].begin(),*it-1,sig);
}

void calc_ans()
{
	int ans=n-tr[1].sum-nmax_cx(1,1,n,1,tr[1].l0)-nmax_cx(1,1,n,tr[1].r0+1,n);
	printf("%d\n",ans);
}

int main()
{
	scanf("%d %d",&n,&q);
	fo(i,1,n)
	{
		scanf("%d",&a[i]);
		maxa=max(maxa,a[i]);
		pos[a[i]].insert(i);
	}
	
	tr_js(1,0,n);
	fo(i,1,maxa) modify(i,1);
	
	calc_ans();
	while (q--)
	{
		int x,y;
		scanf("%d %d",&x,&y);
		
		modify(a[x],-1);
		pos[a[x]].erase(x);
		modify(a[x],1);
		
		modify(y,-1);
		pos[y].insert(x);
		modify(y,1);
		a[x]=y;
		
		calc_ans();
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值