给定一个长 的元素两两不同的序列 ,,若 ,则让 向 连一条无向边。
次修改数组某个位置的值,每次修改后输出图中连通块个数。
,,保证任意时刻数组中元素两两不同。
首先有个结论:
若 和 满足 ,则 , 与 、 连通。
证明是显然的。
根据这个结论,每个连通块一定是一个连续段。
那么注意到 , 和 不在同一个连通块中当且仅当 。而由于每个连通块都是连续段,所以连通块个数就是这样的 的个数 。
定义 的前驱 为满足 且 最大的 ,令 ,则一定有:
- ;
- 中 的个数就是连通块个数,因为每个 的 显然都满足 ;
那么用 set 维护前驱后继、线段树维护 中最小值以及最小值个数即可。
代码如下:
#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
const int S=500005;
int n,q,a[S];
int tag[S<<2],mn[S<<2],mnc[S<<2];
set<pair<int,int>> st;
inline void upda(int u)
{
	int ls=u<<1,rs=u<<1|1;
	mnc[u]=0;
	mn[u]=min(mn[ls],mn[rs]);
	if(mn[ls]==mn[u]) mnc[u]+=mnc[ls];
	if(mn[rs]==mn[u]) mnc[u]+=mnc[rs];
}
inline void addtag(int u,int val)
{
	tag[u]+=val;
	mn[u]+=val;
}
inline void dwntag(int u)
{
	if(tag[u]==0) return;
	addtag(u<<1,tag[u]),addtag(u<<1|1,tag[u]);
	tag[u]=0;
}
void build(int u,int l,int r)
{
	if(l==r) return tag[u]=0,mn[u]=0,mnc[u]=1,void();
	int mid=l+r>>1;
	build(u<<1,l,mid),build(u<<1|1,mid+1,r);
	upda(u);
}
void upd(int u,int l,int r,int L,int R,int val)
{
	if(l>R||r<L) return;
	if(l>=L&&r<=R) return addtag(u,val);
	dwntag(u);
	int mid=l+r>>1;
	if(L<=mid) upd(u<<1,l,mid,L,R,val);
	if(R>=mid+1) upd(u<<1|1,mid+1,r,L,R,val);
	upda(u);
}
inline void updd(int l,int r,int x)
{
	if(l==0||r==n+1) return;
	r=min(r,n);
	if(l+1>r) return;
	upd(1,1,n,l+1,r,x);
}
inline void ins(int p,int x)
{
	st.insert(make_pair(x,p));
	auto lb=st.lower_bound(make_pair(x,p));
	auto rb=st.lower_bound(make_pair(x,p));
	lb--,rb++;
	updd(lb->second,rb->second,-1);
	updd(lb->second,p,1);
	updd(p,rb->second,1);
}
inline void del(int p,int x)
{
	auto lb=st.lower_bound(make_pair(x,p));
	auto rb=st.lower_bound(make_pair(x,p));
	lb--,rb++;
	updd(lb->second,p,-1);
	updd(p,rb->second,-1);
	updd(lb->second,rb->second,1);
	st.erase(make_pair(x,p));
}
int main()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	build(1,1,n);
	st.insert(make_pair(-1e9,0)),st.insert(make_pair(1e9,n+1));
	for(int i=1;i<=n;i++) ins(i,a[i]);
	while(q-->0)
	{
		int p,x;
		scanf("%d%d",&p,&x);
		del(p,a[p]);
		a[p]=x;
		ins(p,a[p]);
		printf("%d\n",mnc[1]);
	}
	return 0;
}
