树状数组题目。
比赛的时候一个小时就有人切掉了,简直恐怖。。。
题意很明确,给定一个区间,问这个区间中和其他数都互质的数的个数。
这题关键在于预处理,先处理出每个数的有效范围,即左端到哪里一直互质和右端到哪里一直互质,那么对于这个数来书,在这个范围内都是有效地,一旦超出了这个数的左区间或者右区间,那么这个数便是无效的。
然后,将所有询问按照左区间非递减的顺序排序,维护一颗树状数组,可以这么想,对于一个数,由于我是从左向右依次更新的,如果我第一次更新到这个数的有效区间的左边界l后一个数的时候,那么,由于询问也是按照从小到大的顺序排序的,此时我的询问最小的左边界也是l+1,那么左边界对于这个数来说就不是限制因素了,因为对于所有剩余的询问区间这个数左边的数都跟这个数是互质的,然后我需要限制的就是右边界了,一个很简单的处理方式就是在这个数的位置+1,在右边界的位置-1,这样便维护了处理到l+1的位置的情况了,然后,当我处理完询问的左边界在l+1的询问后,我下一次处理的肯定至少是l+2的询问了,此时l+1这个数已经被舍弃了,所有有效区间左边界在l+1的数便不受左边界的限制了,我便可以按照上面的方法更新这些数,还有关键一点,由于我把l+1这个数舍弃了,那么它的右边界我之前减去的1也就无意义了,要把这个1再加上,这样便成功维护了一颗符合题意的树状数组。
附代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define delf int m=(l+r)>>1
using namespace std;
const int MAX=200000+10;
int tree[MAX];
int v[MAX];
int vl[MAX]; //左端到哪
int vr[MAX]; //右端到哪
int mark[MAX]; //记录上一个素数出现的位置
int ans[MAX];
int n,m;
int cnt;
vector <int> vc[MAX];
vector <int> pri[MAX];
void init()
{
for (int i=2;i<=200000;i++)
for (int t=i;t<=200000;t+=i)
pri[t].push_back(i);
return ;
}
void pre() //预处理出每个数的左边第一个非互质的位置和右边第一个非互质的位置
{
for (int i=0;i<=n;i++)
vc[i].clear();
for (int i=1;i<=n;i++)
{
for (int t=0;t<pri[v[i]].size();t++)
{
int p=pri[v[i]][t];
if (mark[p]==0)
{
mark[p]=i;
continue ;
}
int a=mark[p];
if (vr[a]==0)
vr[a]=i;
if (vl[i]<a)
vl[i]=a;
mark[p]=i;
}
vc[vl[i]].push_back(i);
}
return ;
}
struct node
{
int l,r,id;
} q[MAX];
bool cmp(node a,node b)
{
return a.l<b.l;
}
int lowbit(int a)
{
return (a)&(-a);
}
int sum(int a)
{
int s=0;
while (a>0)
{
s+=tree[a];
a-=lowbit(a);
}
return s;
}
void update(int a,int b)
{
while (a<=n)
{
tree[a]+=b;
a+=lowbit(a);
}
}
int main()
{
init();
while (~scanf("%d%d",&n,&m)&&n+m)
{
for (int i=1;i<=n;i++)
scanf("%d",&v[i]);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+m+1,cmp);
for (int i=1;i<=n;i++)
tree[i]=0;
for (int i=1;i<=n;i++)
vl[i]=0;
for (int i=1;i<=n;i++)
vr[i]=0;
memset(mark,0,sizeof(mark));
pre();
int cur=1;
for (int i=0;i<=n;i++)
{
while (q[cur].l==i)
{
ans[q[cur].id]=sum(q[cur].r)-sum(q[cur].l-1);
cur++;
}
for (int t=0;t<vc[i].size();t++)
{
update(vc[i][t],1);
if (vr[vc[i][t]]!=0)
update(vr[vc[i][t]],-1);
}
if (vr[i]!=0)
update(vr[i],1);
}
for (int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}
}