又是一道***的**卡常题 在HDU上不是RE就是MLE 在uva上秒过 真是*****了 天天被卡常
考虑CDQ分治 对每个数预处理所有素因子 然后看所有素因子在左右其他位置出现的最大和最小下标 然后对于每个查询就转为查询区间内有多少数的左右第一个非互素的数位置都在查询范围之外的问题了 以查询和修改的位置作为第一维 左端点为第二维 线段树或树状数组维护第三维
后来看了别人博客 知道了用线段树或树状数组也可以
别人的思路:
处理出每个数,最左边能互质到的位置L[i],以及右边R[i]。(具体方法看代码)
然后用树状数组维护区间的覆盖,按l离线查询。
然后从左往右扫。对于当前位置p,找出所有L[i]==p的数。然后i位置+1,R[i]+1的位置-1。因为p以及p以后的位置,这个L[i]都能覆盖到。
离开位置p的时候,要把p位置这个数的覆盖去掉。即p位置-1,R[p]+1的位置+1。
如果p位置上有查询,那么sum(r)就是答案。
CDQ分治
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
struct node
{
int tp;
int x;
int y;
int z;
int val;
};
vector <int> pre[200010];
node order[600010],tmp[600010];
int sum[200010];
int ary[200010],l[200010],r[200010],pos[200010],ans[200010];
int n,q,tot;
bool cmp(node n1,node n2)
{
if(n1.z==n2.z) return n1.tp<n2.tp;
else return n1.z<n2.z;
}
int lowbit(int x)
{
return x&(-x);
}
void init()
{
int i,j,t;
for(i=1;i<=200000;i++)
{
t=i;
for(j=2;j*j<=t;j++)
{
if(t%j==0)
{
pre[i].push_back(j);
while(t%j==0) t/=j;
}
}
if(t!=1) pre[i].push_back(t);
}
}
void update(int tar,int val)
{
int i;
for(i=tar;i<=n+1;i+=lowbit(i)) sum[i]+=val;
}
int query(int tar)
{
int res,i;
res=0;
for(i=tar;i>=1;i-=lowbit(i)) res+=sum[i];
return res;
}
void cdq(int l,int r)
{
int m,p,q,cnt,i;
if(l==r) return;
m=(l+r)/2;
cdq(l,m);
cdq(m+1,r);
p=l,q=m+1,cnt=l;
while(p<=m&&q<=r)
{
if(order[p].x<order[q].x)
{
if(order[p].tp==1) update(order[p].y,order[p].val);
tmp[cnt++]=order[p++];
}
else
{
if(order[q].tp==2) ans[order[q].val]-=(query(n+1)-query(order[q].y));
else if(order[q].tp==3) ans[order[q].val]+=(query(n+1)-query(order[q].y));
tmp[cnt++]=order[q++];
}
}
while(q<=r)
{
if(order[q].tp==2) ans[order[q].val]-=(query(n+1)-query(order[q].y));
else if(order[q].tp==3) ans[order[q].val]+=(query(n+1)-query(order[q].y));
tmp[cnt++]=order[q++];
}
for(i=l;i<p;i++)
{
if(order[i].tp==1) update(order[i].y,-order[i].val);
}
while(p<=m) tmp[cnt++]=order[p++];
for(i=l;i<=r;i++) order[i]=tmp[i];
}
int main()
{
int i,j,pl,pr;
init();
while(scanf("%d%d",&n,&q)!=EOF)
{
if(n==0&&q==0) break;
for(i=1;i<=n;i++) scanf("%d",&ary[i]);
for(i=1;i<=200000;i++) pos[i]=0;
for(i=1;i<=n;i++)
{
l[i]=0;
for(j=0;j<pre[ary[i]].size();j++)
{
l[i]=max(l[i],pos[pre[ary[i]][j]]);
pos[pre[ary[i]][j]]=i;
}
}
for(i=1;i<=200000;i++) pos[i]=n+1;
for(i=n;i>=1;i--)
{
r[i]=n+1;
for(j=0;j<pre[ary[i]].size();j++)
{
r[i]=min(r[i],pos[pre[ary[i]][j]]);
pos[pre[ary[i]][j]]=i;
}
}
tot=0;
for(i=1;i<=n;i++)
{
tot++;
order[tot].tp=1;
order[tot].x=l[i];
order[tot].y=r[i];
order[tot].z=i;
order[tot].val=1;
}
for(i=1;i<=q;i++)
{
scanf("%d%d",&pl,&pr);
tot++;
order[tot].tp=2;
order[tot].x=pl;
order[tot].y=pr;
order[tot].z=pl-1;
order[tot].val=i;
tot++;
order[tot].tp=3;
order[tot].x=pl;
order[tot].y=pr;
order[tot].z=pr;
order[tot].val=i;
}
sort(order+1,order+tot+1,cmp);
memset(sum,0,sizeof(sum));
memset(ans,0,sizeof(ans));
cdq(1,tot);
for(i=1;i<=q;i++) printf("%d\n",ans[i]);
}
return 0;
}
树状数组
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
struct node1
{
int m;
int r;
};
struct node2
{
int id;
int r;
};
vector <int> pre[200010];
vector <node1> gou[200010];
vector <node2> order[200010];
int sum[200010];
int ary[200010],l[200010],r[200010],pos[200010],ans[200010];
int n,q;
int lowbit(int x)
{
return x&(-x);
}
void init()
{
int i,j,t;
for(i=1;i<=200000;i++)
{
t=i;
for(j=2;j*j<=t;j++)
{
if(t%j==0)
{
pre[i].push_back(j);
while(t%j==0) t/=j;
}
}
if(t!=1) pre[i].push_back(t);
}
}
void update(int tar,int val)
{
int i;
for(i=tar;i<=n;i+=lowbit(i)) sum[i]+=val;
}
int query(int tar)
{
int res,i;
res=0;
for(i=tar;i>=1;i-=lowbit(i)) res+=sum[i];
return res;
}
int main()
{
node1 tmp1;
node2 tmp2;
int i,j,pl,pr;
init();
while(scanf("%d%d",&n,&q)!=EOF)
{
if(n==0&&q==0) break;
for(i=1;i<=n;i++) scanf("%d",&ary[i]);
for(i=1;i<=200000;i++) pos[i]=0;
for(i=1;i<=n;i++)
{
l[i]=0;
for(j=0;j<pre[ary[i]].size();j++)
{
l[i]=max(l[i],pos[pre[ary[i]][j]]);
pos[pre[ary[i]][j]]=i;
}
}
for(i=1;i<=200000;i++) pos[i]=n+1;
for(i=n;i>=1;i--)
{
r[i]=n+1;
for(j=0;j<pre[ary[i]].size();j++)
{
r[i]=min(r[i],pos[pre[ary[i]][j]]);
pos[pre[ary[i]][j]]=i;
}
}
for(i=0;i<=200000;i++) gou[i].clear();
for(i=0;i<=200000;i++) order[i].clear();
for(i=1;i<=n;i++)
{
tmp1.m=i,tmp1.r=r[i];
gou[l[i]].push_back(tmp1);
}
for(i=1;i<=q;i++)
{
scanf("%d%d",&pl,&pr);
tmp2.id=i,tmp2.r=pr;
order[pl].push_back(tmp2);
}
memset(sum,0,sizeof(sum));
memset(ans,0,sizeof(ans));
for(i=1;i<=n;i++)
{
for(j=0;j<gou[i-1].size();j++)
{
update(gou[i-1][j].m,1);
update(gou[i-1][j].r,-1);
}
for(j=0;j<order[i].size();j++)
{
ans[order[i][j].id]=query(order[i][j].r);
}
update(i,-1);
update(r[i],1);
}
for(i=1;i<=q;i++) printf("%d\n",ans[i]);
}
return 0;
}