一个区间为好区间当且仅当$max_{lle ile r}a_{i}-min_{lle ile r}a_{i}=r-l$,考虑固定右端点$r$,维护所有左端点$l$的上述式子左-右的值,那么答案即求0的个数,也就是最小值的个数(该值必然非负且$l=r$时必然为0)
如何维护右端点移动:先将所有位置减1,再用单调栈找到之前第一个小于和大于其的位置,然后由于这两个位置中必然有一个为$r-1$,不需要考虑,记剩下的位置为$x$,不妨假设$a_{x}>a_{r}$
那么也就是考虑以$a[1..r]$这个前缀的后缀最大值,也即单调栈中被$r$弹出的元素,因此对于被弹出的两个元素中间,加上$a_{r}-先弹出的元素$即可($a_{x}<a_{r}$类似)
对于多组询问,将询问离线并记录在对应位置上,即查询区间$[l,r]$最小值次数(令未修改的位置为1)
维护一个时间标记,表示当前的sum已经统计到该时间,再下传修改同时也要下传时间标记,因此在上一个时间标记到现在其最小值次数不变,即可维护
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 120005 4 #define ll long long 5 #define L (k<<1) 6 #define R (L+1) 7 #define mid (l+r>>1) 8 vector<pair<int,int> >v[N]; 9 int n,m,x,y,a[N],mn[N],mx[N],f[N<<2],tag[N<<2],tim[N<<2],tot[N<<2]; 10 ll ans[N],sum[N<<2]; 11 void upd(int k,int x){ 12 f[k]+=x; 13 tag[k]+=x; 14 } 15 void upd_time(int k,int x){ 16 sum[k]+=1LL*x*tot[k]; 17 tim[k]+=x; 18 } 19 void up(int k){ 20 f[k]=min(f[L],f[R]); 21 tot[k]=0; 22 if (f[k]==f[L])tot[k]+=tot[L]; 23 if (f[k]==f[R])tot[k]+=tot[R]; 24 sum[k]=sum[L]+sum[R]; 25 } 26 void down(int k){ 27 upd(L,tag[k]); 28 upd(R,tag[k]); 29 tag[k]=0; 30 if (f[L]==f[k])upd_time(L,tim[k]); 31 if (f[R]==f[k])upd_time(R,tim[k]); 32 tim[k]=0; 33 } 34 void build(int k,int l,int r){ 35 f[k]=1; 36 tot[k]=r-l+1; 37 if (l==r)return; 38 build(L,l,mid); 39 build(R,mid+1,r); 40 } 41 void update(int k,int l,int r,int x,int y,int z){ 42 if ((l>y)||(x>r))return; 43 if ((x<=l)&&(r<=y)){ 44 upd(k,z); 45 return; 46 } 47 down(k); 48 update(L,l,mid,x,y,z); 49 update(R,mid+1,r,x,y,z); 50 up(k); 51 } 52 ll query(int k,int l,int r,int x,int y){ 53 if ((l>y)||(x>r))return 0; 54 if ((x<=l)&&(r<=y))return sum[k]; 55 down(k); 56 return query(L,l,mid,x,y)+query(R,mid+1,r,x,y); 57 } 58 int main(){ 59 scanf("%d",&n); 60 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 61 scanf("%d",&m); 62 for(int i=1;i<=m;i++){ 63 scanf("%d%d",&x,&y); 64 v[y].push_back(make_pair(x,i)); 65 } 66 build(1,1,n); 67 for(int i=1;i<=n;i++){ 68 update(1,1,n,1,i,-1); 69 while ((mn[0])&&(a[mn[mn[0]]]>a[i])){ 70 if (mn[0]==1)update(1,1,n,1,mn[mn[0]],a[mn[mn[0]]]-a[i]); 71 else update(1,1,n,mn[mn[0]-1]+1,mn[mn[0]],a[mn[mn[0]]]-a[i]); 72 mn[0]--; 73 } 74 mn[++mn[0]]=i; 75 while ((mx[0])&&(a[mx[mx[0]]]<a[i])){ 76 if (mx[0]==1)update(1,1,n,1,mx[mx[0]],a[i]-a[mx[mx[0]]]); 77 else update(1,1,n,mx[mx[0]-1]+1,mx[mx[0]],a[i]-a[mx[mx[0]]]); 78 mx[0]--; 79 } 80 mx[++mx[0]]=i; 81 upd_time(1,1); 82 for(int j=0;j<v[i].size();j++)ans[v[i][j].second]=query(1,1,n,v[i][j].first,i); 83 } 84 for(int i=1;i<=m;i++)printf("%lld ",ans[i]); 85 }