【洛谷4215】踩氣球(線段樹)
阿新 • • 發佈:2018-12-14
題目:
分析:
感覺思路有點像線段樹分治?
把所有區間插到線段樹上。我一開始的想法是修改時給樹上一條鏈上包含的所有熊孩子的值都減\(1\),然後發現這個單次最壞是\(O(m)\)的,gg。
可以記錄每個熊孩子被分成了多少個非零的區間。修改時如果某個區間變成\(0\)了,那麼就給包含該區間的熊孩子的區間數減\(1\),這樣均攤最多有\(m\log m\)個區間,總複雜度\(O(q\log n+m\log n)\)。和暴力相比,這樣做相當於把每個熊孩子最多分的段數從\(n\)(每個位置一段)變成了\(\log n\)。
程式碼:
#include <cstdio> #include <algorithm> #include <cstring> #include <cctype> using namespace std; #define _ 0 namespace zyt { template<typename T> inline void read(T &x) { char c; bool f = false; x = 0; do c = getchar(); while (c != '-' && !isdigit(c)); if (c == '-') f = true, c = getchar(); do x = x * 10 + c - '0', c = getchar(); while (isdigit(c)); if (f) x = -x; } template<typename T> inline void write(T x) { static char buf[20]; char *pos = buf; if (x < 0) putchar('-'), x = -x; do *pos++ = x % 10 + '0'; while (x /= 10); while (pos > buf) putchar(*--pos); } const int N = 1e5 + 10, B = 17; struct edge { int to, next; }e[N * B]; int n, m, q, arr[N], seg[N], head[1 << (B + 1) | 11], ecnt, ans; inline void add(const int a, const int b) { e[ecnt] = (edge){b, head[a]}, head[a] = ecnt++; } namespace Segment_Tree { struct node { int sum; }tree[1 << (B + 1) | 11]; inline void update(const int rot) { tree[rot].sum = tree[rot << 1].sum + tree[rot << 1 | 1].sum; } void build(const int rot, const int lt, const int rt) { head[rot] = -1; if (lt == rt) { tree[rot].sum = arr[lt]; return; } int mid = (lt + rt) >> 1; build(rot << 1, lt, mid); build(rot << 1 | 1, mid + 1, rt); update(rot); } void insert(const int rot, const int lt, const int rt, const int ls, const int rs, const int id) { if (ls <= lt && rt <= rs) { if (tree[rot].sum) ++seg[id]; add(rot, id); return; } int mid = (lt + rt) >> 1; if (ls <= mid) insert(rot << 1, lt, mid, ls, rs, id); if (rs > mid) insert(rot << 1 | 1, mid + 1, rt, ls, rs, id); } void change(const int rot, const int lt, const int rt, const int pos) { if (lt == rt) --tree[rot].sum; else { int mid = (lt + rt) >> 1; if (pos <= mid) change(rot << 1, lt, mid, pos); else change(rot << 1 | 1, mid + 1, rt, pos); update(rot); } if (!tree[rot].sum) for (int i = head[rot]; ~i; i = e[i].next) if (!--seg[e[i].to]) ++ans; } } int work() { using namespace Segment_Tree; read(n), read(m); for (int i = 1; i <= n; i++) read(arr[i]); build(1, 1, n); for (int i = 1; i <= m; i++) { int l, r; read(l), read(r); insert(1, 1, n, l, r, i); if (!seg[i]) ++ans; } read(q); int lastans = 0; while (q--) { int x; read(x); x = (x + lastans - 1) % n + 1; change(1, 1, n, x); write(lastans = ans), putchar('\n'); } return ~~(0^_^0); } } int main() { return zyt::work(); }