题目大意:给定一行n个正整数a[1]..a[n]。m次询问,每次询问给定一个区间[L,R],输出a[L]..a[R]的最大公因数。
因为gcd满足交换律和结合律,所以用线段树维护区间上的gcd值即可。
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX_RANGE = 1010;
int GetGcd(int a, int b)
{
return b ? GetGcd(b, a % b) : a;
}
struct GcdRangeTree
{
private:
int Gcd[MAX_RANGE * 4];
int N;
void PullUp(int cur)
{
Gcd[cur] = GetGcd(Gcd[cur * 2], Gcd[cur * 2 + 1]);
}
void Init(int cur, int sl, int sr, int *a)
{
if (sl == sr)
{
Gcd[cur] = a[sr];
return;
}
int mid = (sl + sr) / 2;
Init(cur * 2, sl, mid, a);
Init(cur * 2 + 1, mid + 1, sr, a);
PullUp(cur);
}
int Query(int cur, int sl, int sr, int al, int ar)
{
//printf("cur(%d,%d) find(%d,%d)\n", sl, sr, al, ar);
if (al <= sl && sr <= ar)
return Gcd[cur];
int ans=0, mid = (sl + sr) / 2;
if (al <= mid)
ans = Query(cur * 2, sl, mid, al, ar);
if (ar > mid)
{
if (ans)
ans = GetGcd(ans, Query(cur * 2 + 1, mid + 1, sr, al, ar));
else
ans = Query(cur * 2 + 1, mid + 1, sr, al, ar);
}
return ans;
}
public:
GcdRangeTree(int n, int *a)
{
N = n;
memset(Gcd, 0, sizeof(Gcd));
Init(1, 1, N, a);
}
int Query(int l, int r)
{
return Query(1, 1, N, l, r);
}
};
int main()
{
int range, opCnt;
static int a[MAX_RANGE];
scanf("%d%d", &range, &opCnt);
for (int i = 1; i <= range; i++)
scanf("%d", a + i);
static GcdRangeTree g(range, a);
while (opCnt--)
{
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", g.Query(l, r));
}
return 0;
}