数据结构
题意:给定10w个数,给出10w个区间询问,问区间中和区间上其
他所有数都互质的数有几个。
很容易想到的是先预处理出每个元素i左边与他互质的到哪儿l[i],右边于他互质的到哪儿r[i],比如2 1 4,l[0]=1,r[0]=2;l[1]=1,r[1]=3,l[2]=2,r[2]=3;
很自然的想法是用树状数组维护区间,在l[i]处+1(其实应该是i),r[i]+1处-1,但这样会有问题,对 2 1 4 3来说查询2 3的时候第0个数还会影响答案
接着很自然的想到把查询离线处理,有序化对于访问过的点,把这个点恢复
还用到一个很神奇的东西,把i在l[i]处用边表存下来,这时候访问到l[i]的时候,就能忽略qr的影响,而把所有的满足左边性质的点都更新进去,这时候就可以用区间减法了
设一个不断移动的扫描线,当扫到一个点的时候,把这个点恢复,扫到一个查询的左区间的时候,把能更新的点都进行更新
#include <cstdio>
#include <cmath>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <set>
#include <map>
#include <sstream>
using namespace std;
#define Debug(x) (cerr << #x << " = " << (x) << endl)
#define Debug2(x, y) (cerr << #x << " = " << (x) << ", " << #y << " = " << (y) << endl)
typedef long long ll;
typedef pair<int,int> pii;
const int mod = 1e9+7;
ll powmod(ll a,ll b) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll powmod(ll a,ll b,ll mod) {ll res=1;a%=mod;for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
bool isprime[maxn];
int pr[maxn/10],pn;
void init(){
memset(isprime,true,sizeof(isprime));
pn = 0;
for(int i=2;i<maxn;i++){
if(isprime[i]){
pr[pn++] = i;
for(int j=2;i*j<maxn;j++){
isprime[i*j] = false;
}
}
}
//Debug(pn);
}
int c[maxn];
int lowbit(int x){
return x&(-x);
}
void update(int p,int x){
while(p < maxn){
c[p] += x;
p += lowbit(p);
}
}
int getsum(int p){
int ans = 0;
while(p > 0){
ans += c[p];
p -= lowbit(p);
}
return ans;
}
int l[maxn];
int r[maxn];
int pre[maxn];
int a[maxn];
int getl(int x,int p){
int ans = 1;
p += 1;
for(int i=0;i<pn&&pr[i]*pr[i]<=x;i++){
if(x % pr[i] == 0){
ans = max(ans,pre[i]);
while(x % pr[i] == 0){
x /= pr[i];
}
pre[i] = p;
}
}
if(x != 1){
int t = lower_bound(pr,pr+pn,x)-pr;
ans = max(ans,pre[t]);
pre[t] = p;
}
return ans;
}
int n,m;
int getr(int x,int p){
int ans = n;
p -= 1;
for(int i=0;i<pn&&pr[i]*pr[i]<=x;i++){
if(x % pr[i] == 0){
ans = min(ans,pre[i]);
while(x % pr[i] == 0){
x /= pr[i];
}
pre[i] = p;
}
}
if(x != 1){
int t = lower_bound(pr,pr+pn,x)-pr;
ans = min(ans,pre[t]);
pre[t] = p;
//Debug2(t,p);
}
return ans;
}
struct op{
int l,r,id;
op(){};
op(int l,int r,int id):l(l),r(r),id(id){};
void in(int i){
scanf("%d%d",&l,&r);
id = i;
}
bool operator < (const op &a) const{
return l < a.l;
}
}q[maxn];
vector<int> g[maxn];
int ans[maxn];
int main(){
init();
while(cin >> n >> m){
if(n == 0 || m == 0)break;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=0;i<pn;i++){
pre[i] = 1;
}
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++){
l[i] = getl(a[i],i);
//update(l[i],1);
}
for(int i=0;i<pn;i++){
//if(i < 3)Debug(pre[i]);
pre[i] = n;
}
for(int i=n;i>=1;i--){
r[i] = getr(a[i],i);
//update(r[i]+1,-1);
}
for(int i=1;i<=n;i++){
//Debug2(l[i],r[i]);
}
for(int i=0;i<m;i++){
q[i].in(i);
}
sort(q,q+m);
for(int i=1;i<=n;i++){
g[i].clear();
}
for(int i=1;i<=n;i++){
g[l[i]].push_back(i);
}
int left = 1;
for(int j=0;j<g[left].size();j++){
update(g[left][j],1);
update(r[g[left][j]]+1,-1);
//Debug(left);
}
for(int i=0;i<m;i++){
//Debug2(q[i].l,q[i].r);
while(left < q[i].l){
update(left,-1);
update(r[left]+1,1);
left ++;
for(int j=0;j<g[left].size();j++){
update(g[left][j],1);
update(r[g[left][j]]+1,-1);
//Debug(left);
}
//Debug(left);
}
ans[q[i].id] = getsum(q[i].r) - getsum(q[i].l-1);
}
for(int i=0;i<m;i++){
printf("%d\n",ans[i]);
}
}
}