题意:
求L到R之间所有子区间gcd的和
思路:
离线处理
先预处理出以每个位置为右端点能得到的所有gcd和最近右端点(用线段树或者由上个点处形成的gcd生成都可),离线之后将扫过的点向左的gcd加入能形成这个gcd的区间,用线段树区间更新区间查询来维护
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,q;
ll num[20010];
struct node
{
int l,r;
ll w;
int tag;
ll lazy;
};
struct node tree[20010*4];
struct qq
{
int l,r;
int id;
bool operator < (const qq &a)const
{
return r<a.r;
}
};
struct qq ques[20010];
struct nnode
{
int pos;
ll w;
nnode(int p_,ll w_)
{
pos=p_;w=w_;
}
};
vector< vector<struct nnode> >v;
ll ans[20010];
void built(int i,int l,int r)
{
tree[i].l=l;
tree[i].r=r;
tree[i].w=0;
tree[i].tag=0;
tree[i].lazy=0;
if(l==r)
return;
int mid=(l+r)>>1;
built(i<<1,l,mid);
built(i<<1|1,mid+1,r);
}
void pushdown(int i)
{
if(tree[i].tag)
{
tree[i<<1].tag=tree[i<<1|1].tag=1;
tree[i<<1].lazy+=tree[i].lazy;
tree[i<<1|1].lazy+=tree[i].lazy;
tree[i<<1].w+=(tree[i<<1].r-tree[i<<1].l+1)*tree[i].lazy;
tree[i<<1|1].w+=(tree[i<<1|1].r-tree[i<<1|1].l+1)*tree[i].lazy;
tree[i].lazy=0;
tree[i].tag=0;
}
}
void updata(int i,int l,int r,ll v)
{
if(tree[i].l==l&&tree[i].r==r)
{
tree[i].w+=v*(tree[i].r-tree[i].l+1);
tree[i].tag=1;
tree[i].lazy+=v;
return;
}
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)
updata(i<<1,l,r,v);
else if(l>mid)
updata(i<<1|1,l,r,v);
else
{
updata(i<<1,l,mid,v);
updata(i<<1|1,mid+1,r,v);
}
tree[i].w=tree[i<<1].w+tree[i<<1|1].w;
}
ll query(int i,int l,int r)
{
pushdown(i);
if(tree[i].l==l&&tree[i].r==r)
{
return tree[i].w;
}
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)
return query(i<<1,l,r);
else if(l>mid)
return query(i<<1|1,l,r);
else
return query(i<<1,l,mid)+query(i<<1|1,mid+1,r);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
v.clear();
v.resize(n+1);
for(int i=1;i<=n;i++)
scanf("%lld",&num[i]);
for(int i=1;i<=n;i++)
{
int pos=i;
ll now=num[i];
v[i].push_back(nnode(pos,now));
for(int j=0;j<v[i-1].size();j++)
{
ll k=__gcd(now,v[i-1][j].w);
if(k!=now)
{
v[i].push_back(nnode(v[i-1][j].pos,k));
now=k;
}
}
}
built(1,1,n);
scanf("%d",&q);
int x,y;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&ques[i].l,&ques[i].r);
ques[i].id=i;
}
sort(ques+1,ques+1+q);
int i,j=1;
for(i=1;i<=q;i++)
{
while(j<=ques[i].r)
{
int pre=1;
for(int k=v[j].size()-1;k>=0;k--)
{
updata(1,pre,v[j][k].pos,v[j][k].w);
pre=v[j][k].pos+1;
}
j++;
}
ans[ques[i].id]=query(1,ques[i].l,ques[i].r);
}
for(int i=1;i<=q;i++)
printf("%lld\n",ans[i]);
}
}