The sum of gcd
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1056 Accepted Submission(s): 465
Problem Description
You have an array
A,the length of
A is
n
Let
f(l,r)=∑ri=l∑rj=igcd(ai,ai+1....aj)
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
First line has one integers
n
Second line has
n integers
Ai
Third line has one integers
Q,the number of questions
Next there are Q lines,each line has two integers
l,
r
1≤T≤3
1≤n,Q≤104
1≤ai≤109
1≤l<r≤n
Output
For each question,you need to print
f(l,r)
Sample Input
2 5 1 2 3 4 5 3 1 3 2 3 1 4 4 4 2 6 9 3 1 3 2 4 2 3
Sample Output
Author
SXYZ
#include
#include
using namespace std;
#define ls t<<1
#define rs (t<<1)|1
const int maxn = 1e4 + 200;
int val[maxn],n, m;
struct node
{
int lg[32], rg[32], ln[32], rn[32], cntl, cntr;
long long sum;
}tree[maxn<<2],ans;
int gcd(int a, int b)
{
if (b == 0)return a;
return gcd(b, a%b);
}
node Union(node a, node b)
{
node ret;
ret.sum = a.sum + b.sum;
for (int i = 0; i < a.cntr; i++)
for (int j = 0; j < b.cntl; j++)
ret.sum += 1ll * gcd(a.rg[i], b.lg[j])*a.rn[i] * b.ln[j];
for (int i = 0; i < a.cntl; i++)
{
ret.lg[i] = a.lg[i];
ret.ln[i] = a.ln[i];
}
for (int i = 0; i < b.cntr; i++)
{
ret.rg[i] = b.rg[i];
ret.rn[i] = b.rn[i];
}
int d = b.rg[b.cntr - 1], pos = b.cntr;
for (int i = 0; i < a.cntr; i++)
{
int tmp = gcd(d, a.rg[i]);
if (tmp == ret.rg[pos - 1])ret.rn[pos - 1] += a.rn[i];
else
{
ret.rg[pos] = tmp;
ret.rn[pos++] = a.rn[i];
}
}
ret.cntr = pos;
d = a.lg[a.cntl - 1], pos = a.cntl;
for (int i = 0; i < b.cntl; i++)
{
int tmp = gcd(d, b.lg[i]);
if (tmp == ret.lg[pos - 1])ret.ln[pos - 1] += b.ln[i];
else {
ret.lg[pos] = tmp;
ret.ln[pos++] = b.ln[i];
}
}
ret.cntl = pos;
return ret;
}
void build(int l, int r, int t)
{
if (l == r)
{
tree[t].cntl = tree[t].cntr = 1;
tree[t].sum = tree[t].rg[0] = tree[t].lg[0] = val[l];
tree[t].ln[0] = tree[t].rn[0] = 1;
return;
}
build(l, (l + r) / 2, ls);
build((l + r) / 2 + 1, r, rs);
tree[t] = Union(tree[ls], tree[rs]);
}
void query(int l, int r,int lt,int rt, int t)
{
if (lt<=l&&rt>=r)
{
if (lt==l)ans = tree[t];
else ans=Union(ans, tree[t]);
return;
}
int mid = (l+r) / 2;
if (lt <= mid)query(l,mid,lt,rt, ls);
if (rt > mid)query(mid+1,r,lt,rt, rs);
}
int main()
{
int t,l,r;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &val[i]);
build(1, n, 1);
scanf("%d", &m);
while (m--)
{
scanf("%d%d", &l, &r);
query(1,n,l,r,1);
printf("%I64d\n", ans.sum);
}
}
return 0;
}