某考试 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; 
}

  

猜你喜欢

转载自www.cnblogs.com/JYYHH/p/8973049.html
t1