题意:给出n个数,有m个查询,每次查询询问区间[L,R]中最多有多少个数与区间中其他数都不互质。
思路:首先预处理一下,把每个数的因子求出来(不包含1,因为1和任何数都互质),这个比较简单……然后再预处理一下第i个数向左最小的和它不互质的数的位置和第i个数向右和它不互质的数的位置(用lf[i]和rn[i]表示)。接下来的操作比较烦,不太好理解。先说下大体思路吧,把所有操作存起来,然后从左到右依次向树状数组里插入,我开始想的是在树状数组每个位置有一个数,一个区间的不互质的和就是区间的和,这样就要让区间的某些位置加一些数,另一些位置减一些数,这个是肯定能构造出来的。那么如何去做呢。
先看一下这个数据吧: 3 6 1 2 5 3
就第4个数来说,构造出来的数就是:0 -1 1 1
这样对于区间为i的查询就可以求出答案了。
构造这个序列的方法如下:
①在第i位+1,在lf[i]-1处-1(这样区间左边在i和lf[i]之间就会加上1)
②从优先队列中取数,如果它的位置等于当前位置,那么就把队列中那个数的位置j处-1,在lf[j]-1处+1。
解释一下这个操作,还以上面那组数据为例,如果只是第一个操作的话,执行完以后的数列是这样的:
3 6 1 2 5 3
0 0 1 1
这样的话,当查询[2,4]时答案就不对了,这是由于这种操作只能保证之前的是正确的,这样就可能要把之前的操作“取消”,答案才会是正确的,因此,对于一个数,当操作到rn[i]+1的位置,就要把这个数之前的操作“取消”,也就是和①进行相反的操作。我用的优先队列存的右边要操作的位置,其实怎么搞都行,不一定要用优先队列,可以用vector存的,当时顺手写了个优先队列,所以……
③看懂第②歩,第三步就和明显了,把rn[i]+1加入优先队列。
之前用线段树写的,后来数据加强线段树就T了,然后想用vector代替优先队列,这样可以把优先队列那儿O(nlog(n))的复杂度变成O(n),结果MLE了……Orz,没办法,写了发树状数组1900ms+过掉了……果然树状数组比线段树快很多,也可能是我线段树写渣了。。。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=200000+10;
int pre[maxn],num[maxn],ans[maxn];
int lf[maxn],rn[maxn];
int sum[maxn];
int n,m;
struct Node
{
int l,pos;
bool operator <(const Node &a) const
{
return l>a.l;
}
};
vector<int>vt[maxn];
vector<Node>querys[maxn];
int lowbit(int x)
{
return x&-x;
}
int Query(int x)
{
int ret=0;
while(x>0)
{
ret+=sum[x];
x-=lowbit(x);
}
return ret;
}
void add(int x,int v)
{
while(x<=n)
{
sum[x]+=v;
x+=lowbit(x);
}
}
void solve()
{
memset(pre,0xff,sizeof(pre));
memset(sum,0,sizeof(sum));
int sz,ntmp,pp;
for(int i=1;i<=n;++i)
{
sz=vt[num[i]].size();
pp=1;
for(int j=0;j<sz;++j)
{
ntmp=vt[num[i]][j];
if(pre[ntmp]!=-1) pp=max(pp,pre[ntmp]+1);
pre[ntmp]=i;
}
lf[i]=pp;
}
memset(pre,0xff,sizeof(pre));
for(int i=n;i>=1;--i)
{
sz=vt[num[i]].size();
pp=n;
for(int j=0;j<sz;++j)
{
ntmp=vt[num[i]][j];
if(pre[ntmp]!=-1) pp=min(pp,pre[ntmp]-1);
pre[ntmp]=i;
}
rn[i]=pp;
}
Node node,tmp;
int x,y;
priority_queue<Node>q;
for(int i=1;i<=n;++i)
{
add(i,1);
x=lf[i]-1;
if(x) add(x,-1);
while(!q.empty())
{
tmp=q.top();
if(tmp.l==i)
{
q.pop();
add(tmp.pos,-1);
x=lf[tmp.pos]-1;
if(x) add(x,1);
}
else break;
}
y=rn[i]+1;
if(y<=n)
{
tmp.l=y;tmp.pos=i;
q.push(tmp);
}
sz=querys[i].size();
for(int j=0;j<sz;++j)
{
node=querys[i][j];
ans[node.pos]=Query(i)-Query(node.l-1);
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
for(int i=2;i<=200000;++i)
for(int j=i;j<=200000;j+=i)
vt[j].push_back(i);
while(~scanf("%d%d",&n,&m))
{
if(n==0&&m==0) break;
for(int i=1;i<=n;++i)
scanf("%d",&num[i]);
for(int i=0;i<=n;++i) querys[i].clear();
int l,r;
Node tmp;
for(int i=0;i<m;++i)
{
scanf("%d%d",&l,&r);
tmp.l=l;tmp.pos=i;
querys[r].push_back(tmp);
}
solve();
for(int i=0;i<m;++i)
printf("%d\n",ans[i]);
}
return 0;
}