#include<bits/stdc++.h>
#define N 200005
using namespace std;
typedef pair<int,int> pii;
vector<int> G[N];
vector<pii> ask[N];
int n,m,x,p[N],f[N],ans[N];
void Insert(int x)
{
int p = x;
while(p <= n)
{
f[p]++;
p += p & (-p);
}
}
int Sum(int x)
{
int p = x,ans = 0;
while(p)
{
ans += f[p];
p -= p & (-p);
}
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
scanf("%d",&x);
p[x] = i;
}
for(int i = 1;i <= n;i++)
for(int j = i;j <= n;j+=i)
{
int x = p[i],y = p[j];
if(x > y) swap(x,y);
G[y].push_back(x);
}
for(int i = 1;i <= m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
ask[r].push_back(make_pair(l,i));
}
for(int i = 1;i <= n;i++)
{
for(int v : G[i]) Insert(v);
for(pii v : ask[i]) ans[v.second] = Sum(i) - Sum(v.first-1);
}
for(int i = 1;i <= m;i++) cout<<ans[i]<<endl;
}
Codeforces Round #182 (Div. 1) Yaroslav and Divisors(離線+樹狀數組)
分析:注意非常重要的一點就是整個數列是一個排列,這樣對於一個1到n的排列成倍數關係的數其實是非常少的,大概是nlogn這個數量級,所以我們先把所有成倍關係的兩元組求出來,這樣設其中下標較大的下標爲x,較小的爲y,那麼問題就轉化爲了每次求一段區間l到r中包含的成對的[x,y]的個數,這個問題有一個經典的離線做法,從左向右掃描序列,每次把小於當前位置i的y對應的x更新到樹狀數組裏邊,那麼對於r = i的詢問,其答案就是sum(r) - sum(l-1).
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.