首页 > 其他 > 详细

【线段树】Gym - 101201J - Shopping

时间:2017-10-07 16:49:42      阅读:309      评论:0      收藏:0      [点我收藏+]

题意: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;
}

【线段树】Gym - 101201J - Shopping

原文:http://www.cnblogs.com/autsky-jadek/p/7634873.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!