CF1209G2 Into Blocks (hard version) 题解

我们考虑一个首尾数字相同的序列,我们容易发现这个序列的每一个值最终一定是一样的,这启发我们把原序列划分成若干个在值域上互不相交的区间,我们容易发现不用修改的点的数量相当于每一个区间的众数的出现次数的和,这里有一个有趣的小trick。

我们考虑一个数第一次出现在\(l_i\),最后一次出现在\(r_i\),那么我们每一回给\([l_i,r_i)\)增加\(1\),最后提出权值为\(0\)的点,这些点就可以把整个区间划分成若干个在值域上互不相交的区间。

现在我们的问题就是如何求出这些区间众数的和,我们考虑另外一个trick,我们把一个值的出现次数放在\(l_i\)处,那么我们统计的相当于一个\(0\)到另外一个\(0\)前的最大值的和,我们可以分为左半部分,中间(已经被\(0\)彻底分开的部分)的和,右半部分,

每一回合并,如果说两边都有\(0\),那么左半部分、右半部分可以直接分别继承左右子树的对应部分,而和则是左子树的和加右子树的和最后加上左子树的右半部分与右子树的左半部分较大的那一个值。

如果只有一边有\(0\),甚至没有\(0\),那么可以直接继承左右子树的值,但是在左边最大值/右边最大值的时候会对整个区间的\(max\)\(\max\),特殊统计一下就可以了,具体见我push_up的第一和第二个if的写法(自认为还是非常容易理解的)。

代码:

#include <bits/stdc++.h>
#define int long long
#define lid (id<<1)
#define rid (id<<1|1)
#define mid ((l+r)/2)
using namespace std;
const int maxn=2e5+10;
set<int>s[maxn];
struct edge{
	int maxx;
	int minn;
	int lazy;
	int sum;
	int lmx;
	int rmx;
}tree[maxn<<2];
int n,m,a[maxn],x,y;
void push_down(int id){
	if(tree[id].lazy){
		tree[lid].lazy+=tree[id].lazy;
		tree[rid].lazy+=tree[id].lazy;
		tree[lid].minn+=tree[id].lazy;
		tree[rid].minn+=tree[id].lazy;
		tree[id].lazy=0;
	}
	return;
}
void push_up(int id){
	tree[id].minn=min(tree[lid].minn,tree[rid].minn);
	tree[id].maxx=max(tree[lid].maxx,tree[rid].maxx);
	if(tree[lid].minn<tree[rid].minn){
		tree[id].lmx=tree[lid].lmx;
		tree[id].sum=tree[lid].sum;
		tree[id].rmx=max(tree[lid].rmx,tree[rid].maxx);
	}
	if(tree[lid].minn>tree[rid].minn){
		tree[id].rmx=tree[rid].rmx;
		tree[id].sum=tree[rid].sum;
		tree[id].lmx=max(tree[lid].maxx,tree[rid].lmx);
	}
	if(tree[lid].minn==tree[rid].minn){
		tree[id].lmx=tree[lid].lmx;
		tree[id].rmx=tree[rid].rmx;
		tree[id].sum=tree[lid].sum+tree[rid].sum+max(tree[lid].rmx,tree[rid].lmx);
	}
	return;
}
void add1(int id,int l,int r,int q,int w,int qw){
	if(q>w){
		return;
	}
	if(q<=l&&r<=w){
		tree[id].minn+=qw;
		tree[id].lazy+=qw;
		return;
	}
	push_down(id);
	if(q<=mid){
		add1(lid,l,mid,q,w,qw);
	}
	if(w>mid){
		add1(rid,mid+1,r,q,w,qw);
	}
	push_up(id);
	return;
}
void add2(int id,int l,int r,int q,int w){
	if(l==r){
		tree[id].maxx+=w;
		tree[id].lmx+=w;
		return;
	}
	push_down(id);
	if(q<=mid){
		add2(lid,l,mid,q,w);
	}
	else{
		add2(rid,mid+1,r,q,w);
	}
	push_up(id);
	return;
}
void update(int q,int w){
	int sz=s[q].size();
	if(!sz){
		return;
	}
	add1(1,1,n,*s[q].begin(),*(--s[q].end())-1,w);
	add2(1,1,n,*s[q].begin(),w*sz);
	return;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s[a[i]].insert(i);
	}
	for(int i=1;i<=n;i++){
		if(s[i].size()){
			update(i,1);
		}
	}
	cout<<n-tree[1].sum-tree[1].lmx-tree[1].rmx<<'\n';
	while(m--){
		cin>>x>>y;
		update(a[x],-1);
		s[a[x]].erase(s[a[x]].find(x));
		update(a[x],1);
		a[x]=y;
		update(a[x],-1);
		s[a[x]].insert(x);
		update(a[x],1);
		cout<<n-tree[1].sum-tree[1].lmx-tree[1].rmx<<'\n';
	}
	return 0;
}
posted @ 2025-05-04 17:50  特别之处  阅读(13)  评论(0)    收藏  举报