CodeChef February Challenge 2018 Chef and odd queries (分塊 + 主席樹)
阿新 • • 發佈:2018-02-17
turn () += -- oid sca com print const
題目鏈接 Chef and odd queries
題意 給定$n$個區間和$q$個詢問,每個詢問給定$m$個點,求這$n$個區間中有多少個包含了$m$個點中的奇數個。
分類操作。
對於$m >$ $\sqrt{n}$的詢問直接一個前綴和依次枚舉,時間復雜度$O(n)$,因為這樣的詢問不會超過$\sqrt{n}$個,
所以規定時間內可以通過。
對於$m <$ $\sqrt{n}$的詢問,兩兩枚舉這$m$個點,枚舉的時間復雜度為$O(n)$
枚舉的點對必滿足這兩個點之間(包括這兩個點)點個數為奇數。
當枚舉的點對為$(x_{i}, x_{j})$的時候,我們要查詢左端點在$[x_{i-1}+1,x_{i}]$,右端點落在$[x_{j},x_{j+1}-1]$的區間個數。
對$x[]$建立主席樹,$root[i]$維護的是坐標範圍 $<= i$的這些點,那麽對於每次查詢可以在$O(logn)$的時間完成。
當然也可以通過離線在樹狀數組上詢問。
時間復雜度$O(n^{\frac{3}{2}}logn)$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 1e5 + 10; const int M = 5e6 + 10; struct node{ int l, r; void scan(){ scanf("%d%d", &l, &r);} friend bool operator < (const node &a, const node &b){ return a.l == b.l ? a.r < b.r : a.l < b.l; } } a[N]; int T, split, tot, ans, n, m, y; int x[N], root[N], s[N], f[M], ls[M], rs[M]; int ins(int x, int l, int r, int val){ int u = ++tot; f[u] = f[x] + 1; ls[u] = ls[x]; rs[u] = rs[x]; if (l == r) return u; int mid = (l + r) >> 1; if (val <= mid) ls[u] = ins(ls[x], l, mid, val); else rs[u] = ins(rs[x], mid + 1, r, val); return u; } int query(int x, int L, int R, int l, int r){ if (l <= L && R <= r) return f[x]; int ret = 0; int mid = (L + R) >> 1; if (l <= mid) ret += query(ls[x], L, mid, l, r); if (r > mid) ret += query(rs[x], mid + 1, R, l, r); return ret; } int solve(int l1, int r1, int l2, int r2){ return query(root[r1], 1, n, l2, r2) - query(root[l1], 1, n, l2, r2); } int main(){ scanf("%d", &T); while (T--){ tot = 0; scanf("%d", &n); rep(i, 1, n) a[i].scan(); sort(a + 1, a + n + 1); for (int i = 1, j = 1; i <= n; ++i){ root[i] = root[i - 1]; for (; j <= n && a[j].l <= i; ++j) root[i] = ins(root[i], 1, n, a[j].r); } scanf("%d", &m); split = int(sqrt(n / log(n)) * 0.8); rep(op, 1, m){ ans = 0; scanf("%d", &y); rep(i, 1, y) scanf("%d", x + i); sort(x + 1, x + y + 1); x[0] = 0, x[y + 1] = n + 1; if (y > split){ s[0] = 0; for (int i = 1, j = 1; i <= n; ++i){ s[i] = s[i - 1]; for (; j <= n && x[j] <= i; ++j) ++s[i]; } rep(i, 1, n) ans += ((s[a[i].r] & 1) ^ (s[a[i].l - 1] & 1)); } else{ rep(i, 1, y){ for (int j = i; j <= y; j += 2){ ans += solve(x[i - 1], x[i], x[j], x[j + 1] - 1); } } } printf("%d\n", ans); } } return 0; }
CodeChef February Challenge 2018 Chef and odd queries (分塊 + 主席樹)