码迷,mamicode.com
首页 > 其他好文 > 详细

【线段树】Gym - 101201J - Shopping

时间:2017-10-07 17:40:27      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:open   opp   ppi   一半   build   clu   highlight   find   题意   

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

标签:open   opp   ppi   一半   build   clu   highlight   find   题意   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!