You are given a sequence {A0, A1, …, AN-1} and an integer set called GS. Defined a function called G(L, R) on A, where G(L, R) = GCD(Ai) (L ≤ i < R) that is the greatest common divisor of all the integers in the subsequence {AL, AL+1, …, AR-1}.
Now There’re several questions for you. Give you three integers L, R and g, where g is an integer in GS. You need to calculate how many integer pairs (l, r) satisfy the condition that G(l, r) = g and L ≤ l < r ≤ R.
Input
Input will consist of multiple test cases. The first line of each case contains three integers N, M, Q (1≤ N, Q≤ 100000, 1 ≤ M ≤ 50), separated by spaces. The second line contains N integers, A0, A1, …, AN-1 (1≤ Ai≤ 100000). The third line contains M integers, indicating the set GS. Every integer in GS is positive and less than 2000. For the next Q line, each line contains three integers, L, R, g (0≤ L< R≤ N, g∈ GS).
Output
For each case, output Q lines. Each line contains an integer, indicating the answer for the query.
Sample Input
4 4 4
1 2 3 4
1 2 3 4
0 4 1
0 4 2
0 4 3
0 4 4
Sample Output
7
1
1
1
思路:
我们可以分析,每一次查询的要素有三个分别是区间左端点、右端点和公因子。
1,由于集合中只有最多50个要查询的公因子,所以可以按照公因子的值分别建立线段树进行查询,这样就解决了公因子;
2,对于每一次查询我们可以固定右端点,将每一次查询放到对应的右端点上去,然后从左往右依次求公因子,更新公因子对应的线段树的值,至于查询我们是固定了右端点的,所以后面的数并不会影响结果,也就是现在就可以查询区间右端点和目前考虑到的右端点相同的区间了。这样就解决了区间端点问题;
3,从左往右由于考虑的数越来越多,求得的公因子的值肯定是非递增的(当出现一个新的端点时候,可能会出现一个新的公因子,也就是新出现的数本身),其中还可能会有重复的值,这样就可以去重减小复杂度了;
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=100005;
int n,m,q,a[maxn],gs[53],rev[maxn];
long long ans[maxn];
struct node
{
int L,g,i;
node(int a=0,int b=0,int c=0)
{
L=a,g=b,i=c;
}
};
vector<node> que[maxn];
struct segtree
{
int add[maxn<<2];
long long sum[maxn<<2];
void build(int l,int r,int rt)
{
add[rt]=0;
sum[rt]=0;
if(l==r) return;
int m=l+r>>1;
build(lson);
build(rson);
}
void pushUp(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushDown(int rt,int l,int r)
{
if(add[rt])
{
int m=l+r>>1;
sum[rt<<1]+=(long long)add[rt]*(m-l+1);
sum[rt<<1|1]+=(long long)add[rt]*(r-m);
add[rt<<1]+=add[rt];
add[rt<<1|1]+=add[rt];
add[rt]=0;
}
}
void update(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
add[rt]++;
sum[rt]+=(r-l+1);
return;
}
int m=l+r>>1;
pushDown(rt,l,r);
if(L<=m)
update(L,R,lson);
if(m<R)
update(L,R,rson);
pushUp(rt);
}
long long query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return sum[rt];
pushDown(rt,l,r);
int m=l+r>>1;
long long ans=0;
if(L<=m) ans+=query(L,R,lson);
if(m<R) ans+=query(L,R,rson);
return ans;
}
} tree[51];
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
void solve()
{
int tot=0;
pair<int,int> sp[maxn];
for(int i=1; i<=n; i++)
{
for(int j=0; j<tot; j++)
{
int tmp=gcd(sp[j].first,a[i]);
sp[j].first=tmp;
}
if(tot>0&&a[i]==sp[tot-1].first)
sp[tot-1].second++;
else
sp[tot++]=make_pair(a[i],1);
if(tot)
{
int tmp=1;
for(int j=1; j<tot; j++)
{
if(sp[j].first==sp[tmp-1].first)
sp[tmp-1].second+=sp[j].second;
else
sp[tmp++]=sp[j];
}
tot=tmp;
}
int cnt=0,L,R,tmp,pos;
for(int j=0; j<tot; j++)
{
tmp=sp[j].first;
pos=rev[tmp];
if(pos!=-1)
{
L=cnt+1;
R=cnt+sp[j].second;
tree[pos].update(L,R,1,n,1);
}
cnt+=sp[j].second;
}
for(int j=0; j<que[i].size(); j++)
{
node tt=que[i][j];
ans[tt.i]=tree[rev[tt.g]].query(tt.L,i,1,n,1);
}
}
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&q))
{
memset(rev,0xff,sizeof rev);
for(int i=0; i<=m; i++)
tree[i].build(1,n,1);
for(int i=1; i<=n; i++)
{
scanf("%d",&a[i]);
que[i].clear();
}
for(int i=1; i<=m; i++)
{
scanf("%d",&gs[i]);
rev[gs[i]]=i;
}
int L,R,g;
for(int i=1; i<=q; i++)
{
scanf("%d%d%d",&L,&R,&g);
L++;
que[R].push_back(node(L,g,i));
}
solve();
for(int i=1; i<=q; i++)
printf("%lld\n",ans[i]);
}
return 0;
}