求[L, R]上,两个数的gcd的最大值
把[1, R]上每一个数的因子都拆出来
如果某一个因子g上一次出现的位置prev[g] >= L
则因子g可能是最大公约数
把[1, R]上每一个数的因子都拆出来
如果某一个因子g上一次出现的位置prev[g] >= L
则因子g可能是最大公约数
我们可以枚举R
这样就是线段树单点更新求区间最大值关键是更新的位置
如果因子曾出现过,我们就用g去更新线段树在prev[g]上的值这样要求我们必须离线
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <queue>
#include <map>
using namespace std;
#define INF 1e9
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define mset(x) memset(x,0,sizeof(x))
typedef __int64 ll;
const int maxn = 50010;
const int maxnode = 50010*4;
int x, x1, x2, val, res;
struct IntervalTree{
int maxv[maxnode];
void init(){
mset(maxv);
}
void update(int o, int l, int r){
if(l==r){
maxv[o] = max(maxv[o], val);
return;
}
int mid = l+(r-l)/2, lc = o*2, rc = o*2+1;
if(x<=mid) update(lc, l, mid);
else update(rc, mid+1, r);
maxv[o] = max( maxv[lc], maxv[rc] );
}
void query(int o, int l, int r){
if(x1<=l && x2>=r){
res = max(res, maxv[o]);
return ;
}
int mid = l+(r-l)/2, lc = o*2, rc = o*2+1;
if(x1<=mid) query(lc, l, mid);
if(x2>mid) query(rc, mid+1, r);
}
}tree;
int t, n, m;
int prev[maxn], a[maxn];
vector<int> factor[maxn];
struct operate{
int l, r, id;
bool operator< (const operate& a)const {
return r < a.r;
}
}op[maxn];
int ans[maxn];
int main(){
// freopen("a.txt","r",stdin);
// freopen(".out","w",stdout);
cin>>t;
while(t--){
cin>>n;
rep(i,1,n){
scanf("%d", &a[i]);
factor[i].clear();
for(int k=1; k<sqrt(a[i]+0.5); k++){
if(a[i]%k==0){
factor[i].push_back(k);
if(k*k!=a[i]) factor[i].push_back(a[i]/k);
}
}
}
cin>>m;
rep(i,1,m){
scanf("%d %d", &op[i].l, &op[i].r);
op[i].id = i;
}
sort(op+1, op+m+1);
tree.init();
int qcnt=1;
mset(prev);
rep(i,1,n){
for(int j=0; j<factor[i].size(); j++){
int g = factor[i][j];
if(prev[g]){
x = prev[g];
val = g;
tree.update(1, 1, n);
}
prev[g] = i;
}
while(qcnt<=m && op[qcnt].r == i){
res = 0;
x1=op[qcnt].l, x2=op[qcnt].r;
tree.query(1,1,n);
ans[op[qcnt].id] = res;
qcnt++;
}
if(qcnt>m) break;
}
rep(i,1,m) printf("%d\n", ans[i]);
}
return 0;
}