# 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;
}