可以很容易的发现,如果选了最高的房子,那么就不能再选了;否则在左边选一坨合法的,在右边选一坨合法的,拼起来还是合法的。
所以我们可以处理出,每个数的控制区间[L,R] (保证这个区间是其他数都小于它的极大区间),以及左边右边最大的比它小的数的位置(在区间里)。
这样我们就可以做到类似线段树的分割并合并区间的答案。
但还有一个问题,,,这样建树的话,最高深度可能是O(N)的,这样不就gg了???
但是数据是随机的啊,,,期望log N. (好像这种根据权值分割树的数据结构叫笛卡尔树?)
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=100005,ha=1e9+7;
int L[maxn],R[maxn],S[maxn],tp,le;
int n,m,H[maxn],V[maxn],Q,W[maxn],ri;
inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x;}
inline int Merge(int o,int x,int y){ return add(add(x*(ll)y%ha,x),add(y,V[o]));}
void build(int o,int l,int r){
if(L[o]) build(L[o],l,o-1);
if(R[o]) build(R[o],o+1,r);
W[o]=Merge(o,W[L[o]],W[R[o]]);
}
int query(int o,int l,int r){
if(!o) return 0;
if(l>=le&&r<=ri) return W[o];
else if(le>o) return query(R[o],o+1,r);
else if(ri<o) return query(L[o],l,o-1);
else return Merge(o,query(L[o],l,o-1),query(R[o],o+1,r));
}
inline void prework(){
for(int i=1;i<=n;i++){
int t=tp;
while(t&&H[S[t]]<H[i]) t--;
if(t<tp) L[i]=S[t+1];
if(t) R[S[t]]=i;
S[tp=++t]=i;
}
build(S[1],1,n);
}
inline void solve(){
while(Q--){
scanf("%d%d",&le,&ri);
printf("%d\n",query(S[1],1,n));
}
}
int main(){
freopen("monopoly.in","r",stdin);
freopen("monopoly.out","w",stdout);
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++) scanf("%d",H+i);
for(int i=1;i<=n;i++) scanf("%d",V+i);
prework();
solve();
return 0;
}