题意:长度为n的序列a,每次从第一个数开始,拿一个严格大于上次拿的数.
m次询问:问将a[p]=x时,总共能拿多少个数? n,m<=1e5, 1<=a[i]<=1e9.
当a[p]变为x时, 要先找到[1:p-1]中选的最后一个y.
此时只要找到[p+1,n]中第一个比max(x,y)大的下标q.线段树维护最值来即可.
预处理出d1[i]表示前缀i选的个数. 以及d2[i]:从a[i]开始选时的个数.
求d1顺着扫一遍, 求d2单调栈预处理后,逆着扫一遍即可.
那么答案就是:d1[p-1] + d2[q] +(y>x?)
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int T,n,m,a[N],R[N],pos[N],cur,d1[N],d2[N];
stack<int> st;
struct node{
int l,r,mx,id;
}t[N<<2];
void push_up(int o){
int ls=o<<1,rs=o<<1|1;
if(t[ls].mx>=t[rs].mx) t[o].mx=t[ls].mx,t[o].id=t[ls].id;
else t[o].mx=t[rs].mx,t[o].id=t[rs].id;
}
void build(int o,int l,int r){
t[o].l=l,t[o].r=r;
if(l==r){
t[o].mx=a[l];
t[o].id=l;
return;
}
int mid=l+r>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
push_up(o);
}
// query [l,r]中第一个大于k的下标.
void query(int o,int ql,int qr,int k){
int l=t[o].l,r=t[o].r;
if(l==r)
{
if(t[o].mx>k) cur=min(cur,l);
return;
}
if(l>=ql&&r<=qr){
if(t[o].mx<=k) return;
if(t[o<<1].mx>k) query(o<<1,ql,qr,k);
else query(o<<1|1,ql,qr,k);
return;
}
int mid=l+r>>1;
if(ql<=mid) query(o<<1,ql,qr,k);
if(qr>mid) query(o<<1|1,ql,qr,k);
}
void solve(){
int p,x;
while(m--){
scanf("%d%d",&p,&x);
int y=a[pos[p-1]],k=max(x,y);
cur=n+1;
query(1,p+1,n,k);
int res=d1[p-1]+d2[cur];
if(x>y) res++;
// cout<<p<<' '<<x<<' '<<y<<' '<<cur<<' '<<d2[cur]<<' '<<'\n';
printf("%d\n",res);
}
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
d1[0]=d2[n+1]=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
while(!st.empty()&&a[st.top()]<a[i])
R[st.top()]=i,st.pop();
st.push(i);
}
while(!st.empty()) R[st.top()]=n+1,st.pop();
int pre=0,val=0;
for(int i=1;i<=n;i++){
d1[i]=d1[i-1],pos[i]=pos[i-1];
if(a[i]>pre) d1[i]++,pre=a[i],pos[i]=i;
}
for(int i=n;i>=1;i--) d2[i]=1+d2[R[i]];
build(1,1,n);
solve();
}
return 0;
}