「CF301D Yaroslav and Divisors」
阿新 • • 發佈:2020-12-01
題目大意
給出一個排列,每次詢問一個區間中滿足一個數為另一個數倍數的數對個數.
分析
首先可以發現整個排列的合法數對數為 \(\mathcal{O}(n\log n)\) 級別,所以可以想到直接去維護這些數對.一個數對由兩個陣列成,這就不容易處理,可以想到離線去處理.對查詢的右端點排序.顯然可以在右端點移動時將新加入的數的貢獻加入.那麼現在就變成了一個字尾查詢的形式,既然是字尾,不妨將一個數對的貢獻放在靠前的數中,這樣在查詢中只有當兩個數都在這個字尾中的時候才會產生貢獻.於是問題變成了單點加,區間查詢,可以用樹狀陣列輕鬆維護.
時間複雜度 \(\mathcal{O}(n\log^2n)\).如果您有低於這個複雜度的做法可以私信我/kel.
程式碼
#include<bits/stdc++.h> #define REP(i,first,last) for(register int i=(first);i<=(last);++i) #define DOW(i,first,last) for(register int i=(first);(last)<=i;--i) #define LL long long #define UI unsigned int #define ULL unsigned long long #define PII pair<int,int> #define PIL pair<int,long long> #define PLI pair<long long,int> #define PLL pair<long long,long long> #define MPR(a,b) make_pair(a,b) namespace IO //快讀模板 using namespace IO; using namespace std; const int MAXN=2e5+5; int n,m; int arr[MAXN]; int id[MAXN]; vector<int>link[MAXN]; class Query { public: int left,right,id; inline bool operator <(const Query &a)const { return right<a.right; } }q[MAXN]; int answer[MAXN]; namespace BIT//單點修改+區間查詢的樹狀陣列 { int tree[MAXN]; inline int Lowbit(const int now) { return now&-now; } inline void Updata(const int place) { for(register int now=place;now<=n;now+=Lowbit(now)) { ++tree[now]; } } inline int Query(const int left,const int right) { register int result=0; for(register int now=right;now;now-=Lowbit(now)) { result+=tree[now]; } for(register int now=left-1;now;now-=Lowbit(now)) { result-=tree[now]; } return result+right-left+1; } } int main() { Read(n,m); REP(i,1,n) { Read(arr[i]); id[arr[i]]=i; } REP(i,1,n)//將數對的貢獻放在靠前的數中 { int top=n/arr[i]; REP(j,2,top) { if(id[arr[i]*j]<i) { link[i].push_back(id[arr[i]*j]); } else { link[id[arr[i]*j]].push_back(i); } } } REP(i,1,m) { Read(q[i].left,q[i].right); q[i].id=i; } sort(q+1,q+1+m); int now=1; REP(i,1,n) { if(link[i].size()) { REP(j,0,link[i].size()-1)//將新加入的數的貢獻放入 { BIT::Updata(link[i][j]); } } while(q[now].right==i) { answer[q[now].id]=BIT::Query(q[now].left,q[now].right); ++now; } } REP(i,1,m) { Writeln(answer[i]); } return 0; }