題意:
給出 個數字,一共 次查詢,每次詢問一個 、,查詢區間 中有多少個不同的 ,其中一個子區間代表一個 。
思路:
區間查詢不同 的個數,這類題像一類套路問題,主要要抓住 的幾個性質。
- 固定右端點,移動左端點, 的值從 不斷變化,要麼不變,要麼至少除 (因爲 最小值爲 )。因此固定右端點之後,只會存在至多 個不同的 ,我們對於相同的 僅保留最靠右的位置。
- 因此對於每個右端點,我們記錄一個 ,存儲對於這個右端點的所有不同的 值。我們可以根據 來更新 。
處理完上述操作之後,我們得到了 個 三元組,然後我們將所有查詢按照右端點排序。
記錄一個 ,不斷右移到查詢的右端點位置,每次移動時將 內的信息存儲到樹狀數組中,即對於每個三元組 ,如果該 未出現過,則在樹狀數組的 位置 ,並設置 。如果該 出現過,則比較 是否比 更大,如果更大,則修改 在樹狀數組中的位置。上述操作即不斷維護 最靠右的出現位置。然後對於每個查詢,直接在樹狀數組中區間查詢即可。
總結:
此題最關鍵的在於發現區間 不斷除 的性質,然後將查詢離線利用樹狀數組不斷維護每個 最後出現的位置即可完成。
代碼:
#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a);
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define per(i,a,b) for(int i = a; i >= b; i--)
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
typedef long long ll;
typedef double db;
const int N = 1e6+100;
const db EPS = 1e-9;
using namespace std;
void dbg() {cout << "\n";}
template<typename T, typename... A> void dbg(T a, A... x) {cout << a << ' '; dbg(x...);}
#define logs(x...) {cout << #x << " -> "; dbg(x);}
int n,q,a[N],vis[N];
ll ans[N],c[N];
struct Node{
int l,r,id;
bool operator < (Node xx) const {
return r < xx.r;
}
}Q[N];
vector<pair<int,int> > base[N];
inline int lowbit(int x) {return x&(~x+1);}
inline void update(int x,ll v) {for(;x<=n;x+=lowbit(x)) c[x] += v;}
inline ll ask(int x){
ll tp = 0;
while(x) tp += c[x], x -= lowbit(x);
return tp;
}
int gcd(int a,int b){
return b == 0 ? a:gcd(b,a%b);
}
int main()
{
while(~scanf("%d%d",&n,&q)){
rep(i,1,n) scanf("%d",&a[i]);
rep(i,1,n) base[i].clear();
rep(i,0,n) c[i] = 0;
//更新每個點的vector
rep(i,1,n){
base[i].push_back(make_pair(i,a[i])); vis[a[i]] = 1;
for(auto &v:base[i-1]){
int tp = gcd(v.second,a[i]);
if(!vis[tp]){
base[i].push_back(make_pair(v.first,tp));
vis[tp] = 1;
}
}
for(auto &v:base[i])
vis[v.second] = 0;
}
rep(i,1,q) scanf("%d%d",&Q[i].l,&Q[i].r), Q[i].id = i;
sort(Q+1,Q+1+q);
int pos = 0;
rep(i,1,q){
while(pos <= Q[i].r){
for(auto &v:base[pos]){
int hp = v.first;
if(hp > vis[v.second]){
if(vis[v.second]) update(vis[v.second],-1);
vis[v.second] = hp;
update(vis[v.second],1);
}
}
pos++;
}
ans[Q[i].id] = ask(Q[i].r)-ask(Q[i].l-1);
}
rep(i,1,q) printf("%lld\n",ans[i]);
memset(vis,0,sizeof vis);
}
return 0;
}