【无标题】F - Rectangle GCD

# H. 矩形GCD

时间限制: 

C/C++ 2s

空间限制: 

C/C++ 1024MB

题目描述

给定一个正整数 �N 和两个长度为 �N 的正整数序列 �=(�1,�2,…,��)A=(A1​,A2​,…,AN​) 和 �=(�1,�2,…,��)B=(B1​,B2​,…,BN​)。

我们有一个 �×�N×N 的网格。第 �i 行和第 �j 列左侧的正方形称为正方形 (�,�)(i,j)。对于每一对整数 (�,�)(i,j) 满足 1≤�,�≤�1≤i,j≤N,正方形 (�,�)(i,j) 上写有 ��+��Ai​+Bj​。处理 �Q 个以下形式的查询。

您被给定了一个四元组整数 ℎ1,ℎ2,�1,�2h1​,h2​,w1​,w2​,满足 1≤ℎ1≤ℎ2≤�,1≤�1≤�2≤�1≤h1​≤h2​≤N,1≤w1​≤w2​≤N。找到长方形区域的最大公约数,该长方形区域的左上角和右下角分别为 (ℎ1,�1)(h1​,w1​) 和 (ℎ2,�2)(h2​,w2​)。

输入描述

第一行,输入两个整数�,�N,Q
接下来一行,输入�N个整数��Ai​
接下来一行,输入�N个整数��Bi​
接下来�Q行,每行四个整数ℎ1,ℎ2,�1,�2h1​,h2​,w1​,w2​

数据范围:

  • 1≤�,�≤2×1051≤N,Q≤2×105
  • 1≤��,��≤1091≤Ai​,Bi​≤109
  • 1≤ℎ1≤ℎ2≤�1≤h1​≤h2​≤N
  • 1≤�1≤�2≤�1≤w1​≤w2​≤N
输出描述

打印 �Q 行。第 �i 行应该包含查询 �i 的答案。

测试样例1
输入
3 5
3 5 2
8 1 3
1 2 2 3
1 3 1 3
1 1 1 1
2 2 2 2
3 3 1 1
输出
2
1
11
6
10
测试样例2
输入
1 1
9
100
1 1 1 1
输出
109
提示

测试样例一解释:

对于第 11 个查询,我们有 �1,2=4,�1,3=6,�2,2=6,�2,3=8C1,2​=4,C1,3​=6,C2,2​=6,C2,3​=8,因此答案是它们的最大公约数,即 22。

解释:就是两个线段树来进行操作。废话不说了,上代码!

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
//最大值 
const ll N = 2e5+7;
//线段树存值 
struct node{
	ll l,r,v;
}treeh[N << 2],treel[N << 2];
//存原始数值和两数之差 
ll vh[N],vl[N],cvh[N],cvl[N];
//建树,用布尔型判定是哪棵树 
void build(ll x,ll l,ll r,bool bj){
	if(!bj)treeh[x] = {l,r};
	else treel[x] = {l,r};
	if(l == r){
		if(!bj)treeh[x].v = cvh[l];
		else treel[x].v = cvl[l];
		return;
	}
	ll mid = l + r >> 1;
	build(x << 1,l,mid,bj);
	build(x << 1 | 1,mid+1,r,bj);
	if(!bj)treeh[x].v=__gcd(treeh[x << 1].v,treeh[x << 1 | 1].v);
	else treel[x].v=__gcd(treel[x << 1].v,treel[x << 1 | 1].v);
	return;
}
//查询 
ll query(ll x,ll l,ll r,bool bj){
	ll sum,f=0;
	if(!bj){
		if(treeh[x].l >= l && treeh[x].r <= r){
			sum=treeh[x].v;
			return sum;
		}
		//这里别忘了去查询 
		ll mid;
		if(!bj)mid = treeh[x].l + treeh[x].r >> 1;
		else mid = treel[x].l + treel[x].r >> 1;
		//要查的在现在的左边 
		if(r <= mid)sum = query(x << 1 ,l,r,bj);
		//要查的在现在的右边
		else if(l > mid)sum = query(x << 1 | 1,l,r,bj);
		//中点在查询的中间 
		else{
			sum=query(x << 1,l,r,bj);
			sum=__gcd(sum,query(x << 1 | 1,l,r,bj));
		}
		return sum;
	}else if(treel[x].l >= l && treel[x].r <= r){
		sum=treel[x].v;
		return sum;
	}
	//和上面的步骤一样 
	ll mid;
	if(!bj)mid = treeh[x].l + treeh[x].r >> 1;
	else mid = treel[x].l + treel[x].r >> 1;
	if(r <= mid)sum = query(x << 1 ,l,r,bj);
	else if(l > mid)sum = query(x << 1 | 1,l,r,bj);
	else{
		sum=query(x << 1,l,r,bj);
		sum=__gcd(sum,query(x << 1 | 1,l,r,bj));
	}
	return sum;
}

void solve(){
	ll n,q;
	cin >> n >> q;
	for(ll i = 1 ; i <= n ; i ++ ){
		cin >> vh[i];
		if(i > 1)cvh[i-1]=abs(vh[i]-vh[i-1]);
	}
	if(n > 1)build(1,1,n-1,false);
	for(ll i = 1 ; i <= n ; i ++ ){
		cin >> vl[i];
		if(i > 1)cvl[i-1]=abs(vl[i]-vl[i-1]);
	}
	if(n > 1)build(1,1,n-1,true);
	while(q--){
		ll x,tx,y,ty;
		cin >> x >> tx >> y >> ty;
		ll ans = vh[x]+vl[y];
		if(x != tx)ans=__gcd(ans,query(1,x,tx-1,false));
		if(y != ty)ans=__gcd(ans,query(1,y,ty-1,true));
		cout << abs(ans) << endl;
	}
	return ;
}

int main(){
	ll t=1;
	while(t--)solve();
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值