1. 程式人生 > >莫隊算法

莫隊算法

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.L
return 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,表示出現至少兩次的數的集合)

莫隊算法