正题
题目大意
nnn个连续的数,第iii个为hih_ihi。有操作
- 给出一个HHH,询问大于等于HHH的数能组成多少个联通块
- 修改一个位置的数。
解题思路
考虑计算连通块尾的数量,我们可以发现一个位置作为联通块尾部当且仅当hi≥Hh_i\geq Hhi≥H且hi+1<Hh_{i+1}<Hhi+1<H。
也就是如果hi+1>hih_{i+1}>h_ihi+1>hi,那hih_ihi能作为尾部的情况当且仅当H∈[hi+1+1,hi]H\in[h_{i+1}+1,h_i]H∈[hi+1+1,hi]。用树状数组维护每个位置的贡献区间即可。
时间复杂度O((n+q)logn)O(\ (n+q)\ \log n)O( (n+q) logn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&-x)
using namespace std;
const int N=2e6+10,S=2e6+1;
int n,m,t[N],a[N];
void Change(int x,int w){x++;while(x<S){t[x]+=w;x+=lowbit(x);}return;
}
int Ask(int x){int ans=0;x++;while(x){ans+=t[x];x-=lowbit(x);}return ans;
}
int main()
{freopen("patrick.in","r",stdin);freopen("patrick.out","w",stdout);scanf("%d%d",&n,&m);a[n+1]=0;for(int i=1;i<=n;i++)scanf("%d",&a[i]);for(int i=0;i<=n;i++)if(a[i]>a[i+1]){Change(a[i+1],1);Change(a[i],-1);}int last=0;for(int i=1;i<=m;i++){char op[5];int x,y;scanf("%s",op);if(op[0]=='Q'){scanf("%d",&x);x^=last;x--;printf("%d\n",last=Ask(x));}else{scanf("%d%d",&x,&y);x^=last;y^=last; if(a[x-1]>a[x])Change(a[x],-1),Change(a[x-1],1);if(a[x]>a[x+1])Change(a[x],1),Change(a[x+1],-1);a[x]=y;if(a[x-1]>a[x])Change(a[x],1),Change(a[x-1],-1);if(a[x]>a[x+1])Change(a[x],-1),Change(a[x+1],1);}}
}