题意:给你n个数,q次询问,每次询问求[L, R]中与其他任何数互质的个数。n, q <= 2e5
思路:
首先预处理出每个数他左边和右边第一个与他不互质的位置pre, post.
然后对询问按右端点排序。(点击打开链接)
(1)对于刚加入点x,树状数组L[x]位置+1 把这个定义为左更新
(2)对于所有R[i]=x的点,树状数组L[i]位置-1,i位置+1 把这个定义为右更新
(3)查询是询问区间 l->r的和
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int a[maxn], pre[maxn], post[maxn], pp[maxn], n, q;
int ans[maxn], tree[maxn];
vector<int> pri[maxn], b[maxn];
struct node
{
int l, r, id;
bool operator <(const node &a) const
{
return r < a.r;
}
}op[maxn];
void init1()
{
for(int i = 2; i < maxn; i++)
if(pri[i].size() == 0)
for(int j = i; j < maxn; j+=i)
pri[j].push_back(i);
}
int lowbit(int x)
{
return x&(-x);
}
void update(int pos, int val)
{
pos++;
while(pos < maxn)
{
tree[pos] += val;
pos += lowbit(pos);
}
}
int query(int pos)
{
pos++;
int res = 0;
while(pos)
{
res += tree[pos];
pos -= lowbit(pos);
}
return res;
}
void init()
{
memset(tree, 0, sizeof(tree));
for(int i = 1; i < maxn; i++) //注意不能只到n
b[i].clear();
for(int i = 1; i < maxn; i++)
pre[i] = 0, post[i] = n+1, pp[i] = 0;
for(int i = 1; i <= n; i++)
{
int now = a[i];
for(int j = 0; j < pri[now].size(); j++)
{
int tmp = pri[now][j];
pre[i] = max(pre[i], pp[tmp]);
post[pp[tmp]] = min(post[pp[tmp]], i);
pp[tmp] = i;
}
}
for(int i = 1; i <= n; i++)
b[post[i]].push_back(i);
}
int main(void)
{
init1();
while(cin >> n >> q)
{
if(!n && !q) break;
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
init();
for(int i = 1; i <= q; i++)
scanf("%d%d", &op[i].l, &op[i].r), op[i].id = i;
sort(op+1, op+1+q);
int p = 1;
for(int i = 1; i <= q; i++)
{
while(p <= n && p <= op[i].r)
{
update(pre[p], 1);
for(int j = 0; j < b[p].size(); j++)
{
int tmp = b[p][j];
update(pre[tmp], -1);
update(tmp, 1);
}
p++;
}
int tmp = query(op[i].r)-query(op[i].l-1);
ans[op[i].id] = op[i].r-op[i].l+1-tmp;
}
for(int i = 1; i <= q; i++)
printf("%d\n", ans[i]);
}
return 0;
}