很好的题目。
首先容易发现连通块一定是一个区间,而这个时候就可以 \(O(nlog^2 n)\) 解决了,具体就是用线段树维护,对于线段树上的节点维护其最左边的连通块的最大值,最右边的连通块的最小值,然后考虑 \(O(log n)\) 合并即可。
但还有更奇妙的做法,就是考虑每个连通块的断点 \(x\),一定是 \(\min_{i=1}^{x} a_i \ge \max_{i=x+1}^{n} a_i\),考虑这个后缀最大值的值为 \(w\),若将序列变成 $[a_i \ge w] $,那一定是一个形如 \(11111..100000\) 的序列,也就是说这个 \(01\) 序列只有两个连通块,所以对于相邻的两个数 \(a_i\) 和 \(a_{i+1}\),\(w\) 在 $[\min(a_i,a_{i+1}),\max(a_i,a_{i+1})) $ 中才会出现一个 \(01\)。
然后用一棵权值线段树维护 \(01\) 个数为 \(1\) 的 \(w\) 的个数即可。
点击查看代码
#include<bits/stdc++.h>
#define fir first
#define sec second
#define int long long
#define pir pair<int,int>
#define mkp(a,b) make_pair(a,b)
using namespace std;
inline int read(){int x=0,f=1; char c=getchar();while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48); c=getchar();}return x*f;
}
const int mod=998244353,inf=1e9,N=5e5+5,V=1e6+5,lim=1e6;
int n,q,a[N];
struct tree{int mn[V<<2],res[V<<2],tg[V<<2];inline void push_up(int p){mn[p]=min(mn[p<<1],mn[p<<1|1]);res[p]=(mn[p<<1]==mn[p])*res[p<<1]+(mn[p<<1|1]==mn[p])*res[p<<1|1];}inline void modify(int p,int k){tg[p]+=k,mn[p]+=k;}inline void push_down(int p){if(tg[p]) modify(p<<1,tg[p]),modify(p<<1|1,tg[p]),tg[p]=0;}inline void upd(int l,int r,int p,int ll,int rr,int k){if(ll<=l&&r<=rr){modify(p,k);return ;}int mid=(l+r)>>1;push_down(p);if(ll<=mid) upd(l,mid,p<<1,ll,rr,k);if(rr>mid) upd(mid+1,r,p<<1|1,ll,rr,k);push_up(p); }inline void add(int l,int r,int p,int num,int k){assert(l<=num&&num<=r);if(l==r){res[p]+=k; return ;}int mid=(l+r)>>1;push_down(p);if(num<=mid) add(l,mid,p<<1,num,k);else add(mid+1,r,p<<1|1,num,k);push_up(p);}
}T;
inline void change(int x,int k){T.upd(0,lim,1,min(a[x],a[x+1]),max(a[x],a[x+1])-1,k);}
signed main(){n=read(),q=read();a[0]=inf,a[n+1]=0;for(int i=1;i<=n;i++) a[i]=read(),T.add(0,lim,1,a[i],1);for(int i=0;i<=n;i++) change(i,1);while(q--){int x=read(),k=read();T.add(0,lim,1,a[x],-1),change(x-1,-1),change(x,-1);a[x]=k;T.add(0,lim,1,a[x],1),change(x-1,1),change(x,1);cout<<T.res[1]<<'\n'; }
}
/*
5 3
25 40 30 20 10
*/