题意:
给定1-n的一个排列。
在一段区间,找两个位置不同的数,使得gcd最大。
思路:
因为给的序列很特殊。
首先容易想到,对1-n每个数作为约数维护一个状态。
把序列中x的倍数,按原来的位置,过滤出来。
对一个询问li, ri
如果其中至少有两个落到[li, ri]区间中,则x为一个可能值。
考虑将询问按右端点从小到大排序。
last[x]
保存x最近出现的位置,初始为0
c[i]
存的是一个潜在最大gcd,在i的右边存在一个数,与ai的gcd是ci
从左到右扫一遍序列,当遍历到ai时
对ai的因子x, 如果
last[x]!=0
,则可以把用x来更新ci,然后更新last
处理询问,就在区间内查询ci的最大值就行了。。
const int N = 50005;
int ai[N], last[N], ans[N], n;
int tr[N<<2], qL, qR;
#define lc o<<1
#define rc o<<1|1
void update(int o, int l, int r, int x, int v) {
if ( l == r ) {
tr[o] = max(v, tr[o]); return;
}
int m = (l + r) >> 1;
if ( x <= m )
update(lc, l, m, x, v);
else
update(rc, m+1, r, x, v);
tr[o] = max ( tr[lc], tr[rc] );
}
int query(int o, int l, int r) {
if ( qL <= l && r <= qR ) return tr[o];
int m = (l + r) >> 1;
if ( qR <= m )
return query(lc, l, m);
else if ( qL > m )
return query(rc, m+1, r);
return max ( query(lc, l, m), query(rc, m+1, r) );
}
struct Q {
int l, r, id;
bool operator < (const Q& rhs) const {
return r < rhs.r;
}
} queries[N];
int main() {
#ifdef _LOCA_ENV_
freopen("input.in", "r", stdin);
#endif // _LOCA_ENV
int t, q;
scanf("%d", &t);
while ( t -- ) {
scanf("%d", &n);
rep(i, 1, n) {
scanf("%d", ai + i);
}
scanf("%d", &q);
rep(i, 0, q-1) {
int l, r;
scanf("%d%d", &l, &r);
queries[i] = (Q) {l, r, i};
}
sort(queries, queries + q);
memset(last, 0, sizeof(last));
memset(tr, 0, sizeof(tr));
int j = 0;
for (int i = 1; i <= n; ++ i) {
for (int x = 1; x * x <= ai[i]; ++ x)
if ( ai[i] % x == 0 ) {
if ( last[x] != 0 ) {
update(1, 1, n, last[x], x);
}
last[x] = i;
int y = ai[i] / x;
if ( y != x ) {
if ( last[y] != 0 ) {
update(1, 1, n, last[y], y);
}
last[y] = i;
}
}
while ( j < q && queries[j].r == i ) {
if ( queries[j].l == queries[j].r ) {
ans[queries[j].id] = 0;
} else {
qL = queries[j].l, qR = queries[j].r;
ans[queries[j].id] = query(1, 1, n);
}
++ j;
}
}
rep(i, 0, q-1) printf("%d\n", ans[i]);
}
return 0;
}