【线段树】Gym - 101201J - Shopping

题意:n个数,m次询问,每次给你一个询问v,l,r,问你v%a[l]%a[l+1]%...%a[r]是多少。

a%b,结果要么不变,要么至少缩小到a的一半,于是用线段树,每次询问当前区间最靠左侧的小于等于当前数的值是多少,只需不超过log次询问就能使该数模完,就行了。

O(n(logn)^2)。

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,m;
ll minv[800005],a[200005];
void buildtree(int rt,int l,int r){
	if(l==r){
		scanf("%I64d",&minv[rt]);
		a[l]=minv[rt];
		return;
	}
	int m=(l+r>>1);
	buildtree(rt<<1,l,m);
	buildtree(rt<<1|1,m+1,r);
	minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
}
int pos;
int find(ll v,int rt,int l,int r){
	if(l==r){
		return l;
	}
	int m=(l+r>>1);
	if(minv[rt<<1]<=v){
		return find(v,rt<<1,l,m);
	}
	else{
		return find(v,rt<<1|1,m+1,r);
	}
}
bool query(int ql,int qr,ll v,int rt,int l,int r){
	if(ql<=l && r<=qr){
		if(minv[rt]<=v){
			pos=find(v,rt,l,r);
			return 1;
		}
		return 0;
	}
	int m=(l+r>>1);
	if(ql<=m){
		if(query(ql,qr,v,rt<<1,l,m)){
			return 1;
		}
	}
	if(m<qr){
		if(query(ql,qr,v,rt<<1|1,m+1,r)){
			return 1;
		}
	}
	return 0;
}
int main(){
//	freopen("j.in","r",stdin);
	ll z;
	int x,y;
	scanf("%d%d",&n,&m);
	buildtree(1,1,n);
	for(int i=1;i<=m;++i){
		scanf("%I64d%d%d",&z,&x,&y);
		while(x<=y && query(x,y,z,1,1,n)){
			z%=a[pos];
			x=pos+1;
		}
		printf("%I64d\n",z);
	}
	return 0;
}
posted @ 2017-10-07 15:36  AutSky_JadeK  阅读(216)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト