莫隊算法
阿新 • • 發佈:2017-07-22
html opera erl 著作權 () text ref ras pan
http://www.cnblogs.com/hzf-sbit/p/4056874.html
https://www.zhihu.com/question/27316467/answer/36260465
處理一類無修改的離線區間詢問問題
復雜度為O(n*sqrt(n)*a),a為單次更新操作的復雜度。
作者:張瑯小強 鏈接:https://www.zhihu.com/question/27316467/answer/130423804 來源:知乎 著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。 ********************************* 問題:有n個數組成一個序列,有m個形如詢問L, R的詢問,每次詢問需要回答區間內至少出現2次的數有哪些。********************************* int len; // 塊長度 struct Query{ int L, R, ID, block; Query(){} // 構造函數重載 Query(int l, int r, int ID):L(l), R(r), ID(ID){ block = l / len; } bool operator < (const Query rhs) const { if(block == rhs.block) return R < rhs.R; // 不是if(L == rhs.L) return R < rhs.R; return L < rhs.Lreturn block < rhs.block; // 否則這就變回算法一了 } }queries[maxm]; map<int, int> buf; inline void insert(int n){ if(buf.count(n)) ++buf[n]; else buf[n] = 1; } inline void erase(int n){ if(--buf[n] == 0) buf.erase(n); } int A[maxn]; // 原序列 queue<int> anss[maxm]; // 存儲答案 int main(){ int n, m; cin >> n; len = (int)sqrt(n); // 塊長度 for(int i = 1; i <= n; i++){ cin >> A[i]; } cin >> m; for(int i = 1; i <= m; i++){ int l, r; cin >> l >> r; queries[i] = Query(l, r, i); } sort(queries + 1, queries + m + 1); int L = 1, R = 1; buf[A[1]] = 1; for(int i = 1; i <= m; i++){ queue<int>& ans = anss[queries[i].ID]; Query &qi = queries[i]; while(R < qi.R) insert(A[++R]); while(L > qi.L) insert(A[--L]); while(R > qi.R) erase(A[R--]); while(L < qi.L) erase(A[L++]); for(map<int, int>::iterator it = buf.begin(); it != buf.end(); ++it){ if(it->second >= 2){ ans.push(it->first); } } } for(int i = 1; i <= m; i++){ queue<int>& ans = anss[i]; while(!ans.empty()){ cout << ans.front() << ‘ ‘; ans.pop(); } cout << endl; } }
在update的同時更新ans。(本題可考慮維護一個set,表示出現至少兩次的數的集合)
莫隊算法