Problem Description
Long long ago, there was an ancient rabbit kingdom in the forest. Every rabbit in this kingdom was not cute but totally pugnacious, so the kingdom was in chaos in season and out of season.
n rabbits were numbered form 1 to n. All rabbits' weight is an integer. For some unknown reason, two rabbits would fight each other if and only if their weight is NOT co-prime.
Now the king had arranged the n rabbits in a line ordered by their numbers. The king planned to send some rabbits into prison. He wanted to know that, if he sent all rabbits between the i-th one and the j-th one(including the i-th one and the j-th one) into prison, how many rabbits in the prison would not fight with others.
Please note that a rabbit would not fight with himself.
n rabbits were numbered form 1 to n. All rabbits' weight is an integer. For some unknown reason, two rabbits would fight each other if and only if their weight is NOT co-prime.
Now the king had arranged the n rabbits in a line ordered by their numbers. The king planned to send some rabbits into prison. He wanted to know that, if he sent all rabbits between the i-th one and the j-th one(including the i-th one and the j-th one) into prison, how many rabbits in the prison would not fight with others.
Please note that a rabbit would not fight with himself.
Input
The input consists of several test cases.
The first line of each test case contains two integer n, m, indicating the number of rabbits and the queries.
The following line contains n integers, and the i-th integer W i indicates the weight of the i-th rabbit.
Then m lines follow. Each line represents a query. It contains two integers L and R, meaning the king wanted to ask about the situation that if he sent all rabbits from the L-th one to the R-th one into prison.
(1 <= n, m, W i <= 200000, 1 <= L <= R <= n)
The input ends with n = 0 and m = 0.
The first line of each test case contains two integer n, m, indicating the number of rabbits and the queries.
The following line contains n integers, and the i-th integer W i indicates the weight of the i-th rabbit.
Then m lines follow. Each line represents a query. It contains two integers L and R, meaning the king wanted to ask about the situation that if he sent all rabbits from the L-th one to the R-th one into prison.
(1 <= n, m, W i <= 200000, 1 <= L <= R <= n)
The input ends with n = 0 and m = 0.
Output
For every query, output one line indicating the answer.
Sample Input
3 2 2 1 4 1 2 1 3 6 4 3 6 1 2 5 3 1 3 4 6 4 4 2 6 0 0
Sample Output
2 1 1 3 1 2HintIn the second case, the answer of the 4-th query is 2, because only 1 and 5 is co-prime with other numbers in the interval [2,6] .
先算出每个数的有效范围,l[i],r[i]代表与第i个数一直互质到的最左端和最右端。这个处理方法是,预处理出一张因子表。然后对每个输入的数,判断其因子出现的最接近它的位置。从左到右扫一遍求出l[i],从右到左扫一遍求出r[i];我们还需要用一个vector记录下左边界为i时的所有数。
我们思考一个范围内,当一个数的l[i]和r[i]都在范围之外时,这个数会被统计在内。反过来讲就是一个范围在一个数的边界之内,当前的数会被统计到范围之内。
我们先对问题进行离线处理,先根据问题的左边界排序。我们需要维护一个树状数组来统计和增减值。
然后我们按照i从1到n扫一遍,i代表的意义是左边界。
1. 当扫到第i个数时,我们统计左边界为i+1的问题(这样范围一定满足左边界,因为右边界接下来也进行了处理,所以可以直接统计)。
2. 我们还需要更新第i个数。i的意义是左边界,因为之后统计的问题左边界都大于i,都满足。所以我们找到所有左边界为i的数,将其+1处理。然后右边界-1处理。这样如果问题的边界大于右边界的话,这个数就不会统计在内。
3. 最后处理完i后,因为以后问题的左边界都大于i,所以第i个数不会再被统计了,所以我们要除去第i个数的影响,就是把其右边界+1(自身为什么不处理,因为处不处理都一样,不会在涉及到它本身了)。
感觉想起来挺复杂的,还是看代码清晰。
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int N=220000;
int p[N],pnum,tree[N],n,m,l[N],r[N],a[N],ans[N],last[N];
vector<int>vec[N],pl[N];
void init()
{
memset(p,0,sizeof(p));
for(int i=2;i<=200000;i++)
if(!p[i])
{
for(int j=i;j<=200000;j+=i)
{
p[j]=1;
vec[j].push_back(i);
}
}
}
struct node
{
int l,r,i;
}q[N];
bool cmp(node a,node b)
{
return a.l<b.l;
}
void find_l()
{
memset(last,0,sizeof(last));
for(int i=0;i<=n;i++) pl[i].clear();
for(int i=1;i<=n;i++)
{
int mmax=0;
for(int j=0;j<vec[a[i]].size();j++)
{
int t=vec[a[i]][j];
if(last[t]>mmax) mmax=last[t];
last[t]=i;
}
l[i]=mmax;
pl[mmax].push_back(i);
}
}
void find_r()
{
memset(last,-1,sizeof(last));
for(int i=n;i>=0;i--)
{
int mmin=n+1;
for(int j=0;j<vec[a[i]].size();j++)
{
int t=vec[a[i]][j];
if(last[t]!=-1&&last[t]<mmin) mmin=last[t];
last[t]=i;
}
r[i]=mmin;
}
}
void add(int k,int num)
{
while(k<=n)
{
tree[k]+=num;
k+=k&-k;
}
}
int sum(int k)
{
int ans=0;
while(k)
{
ans+=tree[k];
k-=k&-k;
}
return ans;
}
int main()
{
init();
while(~scanf("%d%d",&n,&m)&&n+m)
{
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].i=i;;
sort(q+1,q+m+1,cmp);
find_l();
find_r();
int cnt=1;
for(int i=1;i<=n;i++) tree[i]=0;
for(int i=0;i<=n;i++)
{
while(cnt<=m&&q[cnt].l==i)
{
ans[q[cnt].i]=sum(q[cnt].r)-sum(q[cnt].l-1);
cnt++;
}
for(int j=0;j<pl[i].size();j++)
{
add(pl[i][j],1);
add(r[pl[i][j]],-1);
}
add(r[i],1);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
}