题目链接:I. query
题意:
给两个数n,m,分别表示序列中有n个数,和m组询问。
接下来n个数pi,表示1-n的一个排列。
接下来m个询问,输出[l,r]中满足min(pi.pj)=gcd(pi,pj)的对数,即[l,r]区间内有多少对“倍数对”。
数据范围:m≤105,n≤105。
解法:
考虑一个树状数组,原数据a[i]表示从i开始到当前的r,能与i形成的倍数对的个数。那么维护这个数字,再根据询问区间的r排序,更新这个a[i],那对每组询问,答案就是query[l,r]。如何维护这个a[i],是很机智的。(自认为)
首先读入排列p的时候把每个数pi对应的下标存起来。
接着用vector G将每个pi的倍数(且不大于n)的下标推到G[pi]的后面,同时把pi的下标i推到这个倍数后面。
那么G[i]对每个i,都存储了它的因数和倍数的下标,即记录了能和它成对的数字。
将每个G[i]后面的下标从小到大排个序。方便对每个询问依次插入。
AC代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <map>
#include <set>
#include <queue>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x7fffffff;
const int mod = 1e9+7;
const double eps = 1e-5;
const int N = 1e5+10;
void redirect() {
#ifdef LOCAL
freopen("test.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
}
inline ll read() {
ll f=1,x=0;char ch;
do {ch=getchar(); if(ch=='-') f=-1;} while (ch<'0'||ch>'9');
do {x=x*10+ch-'0'; ch=getchar(); } while (ch>='0'&&ch<='9');
return x*f;
}
struct Node{
int l,r;int idx;ll ans;
} Q[N];
bool cmp_1 (Node a, Node b) {
return a.r<b.r;
}
bool cmp_2 (Node a, Node b) {
return a.idx<b.idx;
}
vector<int> G[N];
int n,m;int vis[N];int a[N],pos[N],nxt[N];ll c[N];
int lowbit (int x) {
return x&(-x);
}
void update (int i,ll k) {
while(i <= n){
c[i] += k;
i += lowbit(i);
}
}
ll sufsum (int i) {//A[1-i]的和
ll res = 0;
while (i) {
res += c[i];
i -= lowbit(i);
}
return res;
}
ll query(int l,int r){
return sufsum(r)-sufsum(l-1);
}
int main() {
redirect();
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) {
scanf("%lld",&a[i]); pos[a[i]]=i;
}
for (int i=1;i<=n;i++) {
int t = a[i]*2;
while ( t <= n ) {
G[t].push_back(i);
G[a[i]].push_back(pos[t]);
t+=a[i];
}
}
for(int i=1;i<=n;i++) sort(G[i].begin(),G[i].end());
for ( int i=1;i<=m;i++ ) {
scanf("%d%d", &Q[i].l, &Q[i].r); Q[i].idx = i;
}
sort ( Q+1, Q+m+1, cmp_1 );
int pt=1;
for(int i=1;i<=m;i++){
while( pt<=Q[i].r && pt<=n ) {
int k=0; int x=a[pt];
for ( k = nxt[x]; k < G[x].size(); k++ ) {
if ( G[x][k] < pt ) update(G[x][k],1);
else break;
}
nxt[x] = k;
pt++;
}
Q[i].ans = query(Q[i].l,Q[i].r);
}
sort( Q+1, Q+m+1, cmp_2 );
for(int i=1;i<=m;i++) printf("%lld\n",Q[i].ans);
}
/*
---------------------
author:dragon_bra
---------------------
*/