题目大意:给你一个无序的1~n的排列a,每次询问[l,r]之间任取两个数得到的最大gcd是多少
先对所有询问离线,然后把问题挂在区间的左端点上(右端点也行)
在预处理完质数,再处理一个next数组,表示 i 的任意一个质因子,这样我们分解质因数的时间降低到而不是
因为能对答案产生贡献的都是成对出现的两个数
所以每次记录一个last[i],表示数 i 上一次出现的位置
当遍历到第 i 个数时,分解出它的所有质因数,然后搜出它所有的因子,因子个数大约不会超过,均摊下来就更少了
那么,a[i] 的某个因数 x 就能和 last[x]成为一对,在线段树里的last[x]位置更新答案,即gcd(a[i],a[last[x]]),但不一定是last[x]的最优解,要在last[x]的位置取一个max
询问就是线段树里查询[l,r]的最大值
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 50010
#define M 50
#define ll long long
using namespace std; int n,q,cte,num,nson,T;
int a[N],pr[N],nxt[N],use[N],head[N];
int son[N],d[N],app[N],pw[N],la[N];
struct node{int l,r,id,ans;}Q[N];
struct Edge{int to,nxt;}edge[N];
void ae(int u,int v){
cte++;edge[cte].to=v;edge[cte].nxt=head[u];head[u]=cte;}
int gcd(int x,int y){if(y==)return x;return gcd(y,x%y);}
struct Seg{
#define il inline
int ma[N<<];
il void pushup(int rt){ma[rt]=max(ma[rt<<],ma[rt<<|]);}
void build(int l,int r,int rt)
{
if(l==r) {ma[rt]=;return;}
int mid=(l+r)>>;
build(l,mid,rt<<),build(mid+,r,rt<<|);
pushup(rt);
}
void update(int x,int l,int r,int rt,int w)
{
if(l==r){ma[rt]=max(ma[rt],gcd(w,a[l]));return;}
int mid=(l+r)>>;
if(x<=mid) update(x,l,mid,rt<<,w);
else update(x,mid+,r,rt<<|,w);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R){return ma[rt];}
int mid=(l+r)>>,ans=;
if(L<=mid) ans=max(query(L,R,l,mid,rt<<),ans);
if(R>mid) ans=max(query(L,R,mid+,r,rt<<|),ans);
return ans;
}
#undef il
}seg;
int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=(ret<<)+(ret<<)+c-'';c=getchar();}
return ret*fh;
}
void get_pr()
{
int cnt=;
for(int i=;i<N;i++){
if(!use[i]) pr[++cnt]=i,nxt[i]=i;
for(int j=;j<=cnt&&i*pr[j]<N;j++){
use[i*pr[j]]=,nxt[i*pr[j]]=pr[j];
if(i%pr[j]==) break;
}
}
}
void Div(int x){
num=;int p;
while(x!=){
num++;p=son[num]=nxt[x];d[num]=;
while(x%p==) x/=p,d[num]++;
}
}
void dfs_ap(int k){
if(k==num+){
app[++nson]=;
for(int i=;i<=num;i++)
app[nson]*=pw[i];
return;}
pw[k]=;
for(int j=;j<=d[k];j++)
dfs_ap(k+),pw[k]*=son[k];
}
void solve(int k)
{
Div(a[k]);nson=;dfs_ap();
for(int i=;i<=nson;i++)
{
if(!la[app[i]]) la[app[i]]=k;
else{
seg.update(la[app[i]],,n,,app[i]);
la[app[i]]=k;
}
}
for(int j=head[k];j;j=edge[j].nxt){
int v=edge[j].to;
Q[v].ans=seg.query(Q[v].l,Q[v].r,,n,);
}
}
void init()
{
for(int i=;i<=n;i++)
a[i]=use[N]=head[i]=la[i]=;
for(int i=;i<=q;i++)
Q[i].l=Q[i].r=Q[i].ans=edge[i].to=edge[i].nxt=;
memset(&seg,,sizeof(seg));
cte=;
}
int main()
{
scanf("%d",&T);
get_pr();
for(int t=;t<=T;t++)
{
scanf("%d",&n);
for(int i=;i<=n;i++)
a[i]=gint();
scanf("%d",&q);
for(int i=;i<=q;i++)
Q[i].l=gint(),Q[i].r=gint(),ae(Q[i].l,i);
seg.build(,n,);
for(int i=n;i>=;i--)
solve(i);
for(int i=;i<=q;i++){
if(Q[i].l==Q[i].r) Q[i].ans=;
printf("%d\n",Q[i].ans);
}init();
}
return ;
}