query
Given a permutation pp of length nn, you are asked to answer mm queries, each query can be represented as a pair (l ,r )(l,r), you need to find the number of pair(i ,j)(i,j) such that l \le i < j \le rl≤i
Input
There is two integers n(1 \le n \le 10^5)n(1≤n≤105), m(1 \le m \le 10^5)m(1≤m≤105) in the first line, denoting the length of pp and the number of queries.
In the second line, there is a permutation of length nn, denoting the given permutation pp. It is guaranteed that ppis a permutation of length nn.
For the next mm lines, each line contains two integer l_ili and r_i(1 \le l_i \le r_i \le n)ri(1≤li≤ri≤n), denoting each query.
Output
For each query, print a single line containing only one integer which denotes the number of pair(i,j)(i,j).
样例输入
3 2 1 2 3 1 3 2 3样例输出
2 0
给定一个长度为 n 的连续的序列 p,询问 m 次,在区间 [l, r] 中,有多少组 i、j 使得 min(p[i], p[j]) = gcd(p[i], p[j])。
min(p[i], p[j]) = gcd(p[i], p[j]) 实际上就表示 p[i]、p[j] 成倍数关系。由于询问次数过多,我们可以离线处理好序列中的倍数关系。
首先,读入数据时,我们将每个值对应的位置记录下来。然后,对于 [1, n] 的每个值 p[i],找出序列中与 p[i] 成倍数关系的值 p[j](p[j] = k*p[i], k = 2, 3, 4...),得到它的位置 j,并与 i 构成一个区间 [i, j],可以称之为贡献区间。若 [i, j] 在查询的范围 [l, r] 之内,那么就能为答案贡献 +1。当我们找到所有这样的区间时,将这些贡献区间与询问区间混合,并进行排序,排序的规则是按照区间的左端点从大到小排列,当贡献区间与询问区间的左端点相同时,则贡献区间在前。然后依次处理每个区间,当遇到贡献区间时,说明贡献区间的右端点(含)前的区间都存在一个成倍数点对(因为是按照左端点从大到小处理的,下一个处理的区间的左端点一定小于等于当前区间左端点,所以一定将当前贡献区间包含,当前贡献区间也就能对后续的询问区间的答案产生贡献),我们用树状数组更新这个值;当遇到询问区间时,由于必须完全包含某个贡献区间,该贡献区间才能对答案产生贡献,所以,我们利用树状数组,得到询问区间的右端点前的贡献区间的个数,即为该询问区间的答案。最后,由于询问是离线处理的,所以要根据询问的顺序依次输出答案。
#include
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5+5;
struct query
{
int l, r, k, f;
query() {}
query(int l, int r, int k, int f): l(l), r(r), k(k), f(f) {}
bool operator < (const query& Q) const
{
if(l != Q.l)
return l > Q.l;
return f > Q.f; //让离线先处理
}
}q[maxn<<6];
int n, m;
int pos[maxn], cnt;
int a[maxn], ft[maxn];
int ans[maxn];
int lowbit(int x)
{
return x & -x;
}
void update(int x, int val)
{
while(x <= n)
{
ft[x] += val;
x += lowbit(x);
}
}
int getSum(int x)
{
int ret = 0;
while(x > 0)
{
ret += ft[x];
x -= lowbit(x);
}
return ret;
}
void read()
{
cin >> n >> m;
for(int i = 1; i <= n; ++i)
{
cin >> a[i];
pos[a[i]] = i;
}
int l, r;
for(int i = 0; i < m; ++i)
{
cin >> l >> r;
q[cnt++] = query(l, r, i, 0);
}
}
void solve()
{
for(int i = 1; i <= n; ++i)
for(int j = 2*a[i]; j <= n; j += a[i])
q[cnt++] = query(min(i, pos[j]), max(i, pos[j]), 0, 1);
sort(q, q+cnt);
for(int i = 0; i < cnt; ++i)
{
if(q[i].f)
update(q[i].r, 1);
else
ans[q[i].k] = getSum(q[i].r);
}
for(int i = 0; i < m; ++i)
cout << ans[i] << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
read();
solve();
return 0;
}