某考试 T1 monopoly
可以很容易的发现,如果选了最高的房子,那么就不能再选了;否则在左边选一坨合法的,在右边选一坨合法的,拼起来还是合法的。
所以我们可以处理出,每个数的控制区间[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; }
我爱学习,学习使我快乐