传送门:HDU4777
题意:给出一个长度为n的序列和m个询问,每次询问求[l, r]区间内和区间内其他数都互质的数有多少个。
思路:对于每个位置的数先向左向右预处理出最长互质区间L[i], R[i],然后将所有询问记录下来按左端点排序,遍历每个位置pos,若该位置为某个L[i],则将树状数组 i 位置+1,R[i] 位置 - 1,若某个询问Ql == pos,则该询问就可以直接计算出答案了,这一轮处理完以后,剩余的询问的Ql都大于 i ,因此i位置的数就不会对后续询问产生影响了,则应该将L[i] - 1, R[i] + 1,继续进行下一轮处理。
注意预处理的时候的技巧,记录每个出现过的素因子的最新位置,对于一个位置上的数,其所有素因子的最大位置就是其L[i], R[i]同理可以求得。
本题树状数组的更新和查询可能不是很好理解,推荐一个线段树版的:点击打开链接 搞懂了再研究树状数组的就好多了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define pi acos(-1)
#define MAXN 200010
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>P;
int n;
vector<int> factor[MAXN];
void init()
{
for(int i = 2; i < MAXN; i++)
if(factor[i].empty())
for(int j = i; j < MAXN; j += i)
factor[j].push_back(i);
}
int a[MAXN], L[MAXN], R[MAXN], pos[MAXN], bit[MAXN];
vector<int> p[MAXN];// p[i] := 以i为区间左端点的数的位置
void calc()
{
int u, v;
fill(pos, pos + MAXN, 0);
for(int i = 1; i <= n; i++)
{
L[i] = 1;
for(int j = 0; j < factor[a[i]].size(); j++)
{
u = factor[a[i]][j];
L[i] = max(L[i], pos[u] + 1);
pos[u] = i;
}
p[L[i]].push_back(i);
}
fill(pos, pos + MAXN, n + 1);
for(int i = n; i >= 1; i--)
{
R[i] = n + 1;
for(int j = 0; j < factor[a[i]].size(); j++)
{
u = factor[a[i]][j];
R[i] = min(R[i], pos[u]);
pos[u] = i;
}
}
}
void add(int i, int x)
{
while(i <= n)
{
bit[i] += x;
i += i & -i;
}
}
int sum(int i)
{
int res = 0;
while(i)
{
res += bit[i];
i -= i & -i;
}
return res;
}
struct query{
int l, r, id;
bool operator < (query a) const
{
return l < a.l;
}
}Q[MAXN];
int ans[MAXN];
int main()
{
int q;
init();
while(scanf("%d %d", &n, &q), n + q)
{
memset(bit, 0, sizeof(bit));
for(int i = 1; i <= n; i++)
{
scanf("%d", a + i);
p[i].clear();
}
calc();
for(int i = 0; i < q; i++)
{
scanf("%d %d", &Q[i].l, &Q[i].r);
Q[i].id = i;
}
sort(Q, Q + q);
int now = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < p[i].size(); j++)
{
add(p[i][j], 1);
add(R[p[i][j]], -1);
}
while(now < q && Q[now].l == i)
{
ans[Q[now].id] = sum(Q[now].r) - sum(Q[now].l - 1);
now++;
}
add(R[i], 1);
add(L[i], -1);
if(now == q) break;
}
for(int i = 0; i < q; i++)
printf("%d\n", ans[i]);
}
return 0;
}