题意:给你一个n的排列,有m个询问,每次询问L R,从L到R区间里选出两个数a, b使得gcd(a,b)最大,每次输出最大的gcd
对于x的所有倍数,我们把他们两两结合得到的最大公约数看做x,把所有的找到的位置排个序,如果询问的L R的最大公约数可以是x,那么这个询问的LR区间必然包含所有的位置的某一个相邻的位置,这样的话就可以把相邻的位置看做线段l r,它有个val值x ,那么询问就是询问L R区间所有线段的最大的val值。
线段树版本比树状数组慢了接近一倍!线段树好像写太挫了,1.9秒过。。。
树状数组
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lowbit(x) ((x)&(-x))
using namespace std;
const int maxn = 50005;
int q[maxn], pos[maxn], node[maxn<<2], ans[maxn];
struct PP{
int l, r, val;
bool operator < (const PP &a) const {
return r < a.r;
}
}a[maxn*10], b[maxn];
int max(int a, int b) {
return a > b ? a : b;
}
int n;
void add(int x, int val) {
while(x > 0) {
node[x] = max(node[x], val);
x -= lowbit(x);
}
}
int get_sum(int x) {
int ans = 0;
while(x <= n) {
ans = max(node[x], ans);
x += lowbit(x);
}
return ans;
}
int main() {
int i, j, t, m, x;
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
for(i = 1;i <= n; i++) node[i] = 1;
for(i = 1;i <= n; i++) {
scanf("%d", &x);
pos[x] = i;
}
int tot = 0;
for(i = 2;i <= n/2; i++) {
int num = 0;
for(j = i;j <= n;j += i) {
q[num++] = pos[j];
}
sort(q, q+num);
for(j = 1;j < num; j++) {
a[tot].l = q[j-1];
a[tot].r = q[j];
a[tot++].val = i;
}
}
sort(a, a+tot);
scanf("%d", &m);
for(i = 0;i < m; i++) {
scanf("%d%d", &b[i].l, &b[i].r);
b[i].val = i;
}
sort(b, b+m);
int cur = 0;
for(i = 0;i < m; i++) {
if(b[i].l == b[i].r) {
ans[b[i].val] = 0;continue;
}
for(j = cur;j < tot && a[j].r <= b[i].r; j++)
add(a[j].l, a[j].val);
cur = j;
ans[b[i].val] = get_sum(b[i].l);
}
for(i = 0;i < m; i++)
printf("%d\n", ans[i]);
}
}