SPOJ-DQUERY D-query 莫隊演算法
阿新 • • 發佈:2018-12-16
題意: 給定一個區間和2e5次查詢, 查詢區間[L, R]的不同的數的個數. 分析: 莫隊和主席樹都可以解決, 先離線再處理查詢. 1. 莫隊演算法: 莫隊演算法一般用來處理區間查詢問題, 區間必須離線, 更新操作要簡單的問題. 主要做法是將區間分塊, 然後根據區間的範圍進行排序, 查詢R節點為第一關鍵字, L節點為第二關鍵字. 排序後在進行處理, 算是一種優美的暴力, 莫隊演算法在處理離線區間查詢問題幾乎是無敵的. 對於這道題, 查詢的是不同數的個數, 離線處理時就直接記錄不同的數的個數就好, 算是一道模板題. 2. 主席樹: 待更新. 莫隊演算法程式碼:
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e6 + 10; struct Query { int l, r, id; } Q[MAXN]; int n, m; int L = 1, R = 0, Ans = 0; int pos[MAXN], a[MAXN]; int flag[MAXN], ans[MAXN]; map<int, int> mp; bool cmp(Query x, Query y) { if (pos[x.l] == pos[y.l]) return x.r < y.r; else return pos[x.l] < pos[y.l]; } void add(int x) { if (flag[a[x]] == 0) Ans++; flag[a[x]]++; } void del(int x) { flag[a[x]]--; if (flag[a[x]] == 0) Ans--; } int main() { scanf("%d", &n); int unit = sqrt(n); int sz = 0; for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); if (mp[a[i]] == 0) { mp[a[i]] = ++sz; } a[i] = mp[a[i]]; pos[i] = i / unit + 1; } scanf("%d", &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &Q[i].l, &Q[i].r); Q[i].id = i; } sort(Q + 1, Q + 1 + m, cmp); for (int i = 1; i <= m; i++) { while (L < Q[i].l) { del(L); L++; } while (L > Q[i].l) { L--; add(L); } while (R < Q[i].r) { R++; add(R); } while (R > Q[i].r) { del(R); R--; } ans[Q[i].id] = Ans; } for (int i = 1; i <= m; i++) printf("%d\n", ans[i]); return 0; }
主席樹程式碼:
//待更新