老师说你们做题太少了,这都是套路题。。考了居然都不会。。。
面壁ing。。。
我回来了。。。
好吧它确实是套路题。。。题目要求给一段1-n的序列。。然后每次询问l-r区间中最大的gcd。。。询问1e5,序列1e5.。
自然需要log级的。。根号也可以。毕竟1e5的根号还可以过的。。
我们发现某些数据结构可以来处理每个数的因数在那些地方出现过。比如树状数组(比如主席树)。
然后就可以在这个数出现的时候把它的约数上次出现的地方的最大值更新一下。也就代表他的贡献从上次出现开始都有。
这样把询问离线处理,排序之后每次到达这个位置如果有询问就可以直接处理
但是如果正向处理的话,就很难求出区间的最值(我懒得敲线段树),我们追求最简单写法。。
所以逆向处理之后倒着插入,这样前缀最大值就是目前最大值。。所以确实很套路,也很简单。。。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int val[100005];
int n,Q,T;
int c[100005];
int las[100005];
int ans[100005];
struct node
{
int l1;
int r1;
int pos;
}nnd[100005];
int tt=1;
int cmp(node a,node b)
{
return a.l1>b.l1;
}
int lowbit(int x)
{
return x&-x;
}
void add(int x,int v)
{
while(x<=n)
{
c[x]=max(c[x],v);
x+=lowbit(x);
}
}
int gett(int x)
{
int s=0;
while(x)
{
s=max(s,c[x]);
x-=lowbit(x);
}
return s;
}
void findf(int x,int po)
{
for(int i=1;i*i<=x;i++)
{
if(x%i==0)
{
if(!las[i])
{
las[i]=po;
}else
{
add(las[i],i);
las[i]=po;
}
if(i*i==x)continue;
if(!las[x/i])
{
las[x/i]=po;
}else
{
add(las[x/i],x/i);
las[x/i]=po;
}
}
}
}
void init()
{
memset(las,0,sizeof(las));
memset(c,0,sizeof(c));tt=1;
}
int main()
{
scanf("%d",&T);
while(T--)
{
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
scanf("%d",&Q);
for(int i=1;i<=Q;i++)
{
scanf("%d%d",&nnd[i].l1,&nnd[i].r1);
nnd[i].pos=i;
}
sort(nnd+1,nnd+1+Q,cmp);
for(int i=n;i>=1;i--)
{
findf(val[i],i);
while(nnd[tt].l1==i)
{
ans[nnd[tt].pos]=gett(nnd[tt].r1);
tt++;
}
}
for(int i=1;i<=Q;i++)
{
printf("%d\n",ans[i]);
}
}
return 0;
}