【题目链接】
【思路要点】
- 我们采用线段树直接维护整个序列,每个节点代表一个区间,并在节点上记录:
- 1、在区间内已经找到了人口更高的\(B\)的\(A\)的数量\(Ans\)
- 2、区间内的道路是否全部向左\(All\)或向右\(Arr\)。
- 3、区间内只能到达左端点/只能到达右端点/既可以到达左端点又可以到达右端点的,人口为\(k(0≤k≤75)\)的,还未找到人口更高的\(B\)的\(A\)的数量\(Al_k,Ar_k,Am_k\)(实际上\(Am_k\)至多有一位非零0,但笔者当场没有想到)。
- 4、从区间的左/右端点是否能够到达人口超过\(k(0≤k≤75)\)的\(B\)型城市\(Bl_k,Br_k\)。
- 并且记录区间中所有边反向后的上述信息。
- 上述信息是可以合并的,在实现了信息的合并后,剩余的工作就是线段树的基本操作了。
- 注意本题卡空间,因此笔者只在线段树的非叶节点上存储了上述信息。
- 时间复杂度\(O((N+QLogN)*(LogN+V))\),其中\(V=75\)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 100002; const int MAXM = 77; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct BinaryIndexTree { int n; bool a[MAXN]; void init(int x) { n = x - 1; for (int i = 1; i <= n; i++) a[i] = false; } void modify(int l, int r) { for (int i = l; i <= n; i += i & -i) a[i] ^= true; for (int i = r; i <= n; i += i & -i) a[i] ^= true; } bool query(int pos) { bool ans = false; for (int i = pos; i >= 1; i -= i & -i) ans ^= a[i]; return ans; } } edge; int n, m, val[MAXN]; char type[MAXN]; struct info { int ans, al[MAXM], am[MAXM], ar[MAXM]; bool bl[MAXM], br[MAXM], all, arr; }; info operator + (const info &a, const info &b) { info ans; memcpy(ans.al, a.al, sizeof(a.al)); memcpy(ans.ar, b.ar, sizeof(b.ar)); memset(ans.am, 0, sizeof(ans.am)); memset(ans.bl, false, sizeof(ans.bl)); memset(ans.br, false, sizeof(ans.br)); ans.ans = a.ans + b.ans; ans.all = false; ans.arr = a.arr && b.arr; for (int i = 0; i <= 75; i++) { if (b.bl[i + 1]) ans.ans += a.ar[i] + a.am[i]; else if (b.arr) ans.ar[i] += a.ar[i], ans.am[i] += a.am[i]; else ans.al[i] += a.am[i]; ans.ar[i] += b.am[i]; ans.br[i] = b.br[i]; if (a.arr) ans.bl[i] = a.bl[i] | b.bl[i]; else ans.bl[i] = a.bl[i]; } return ans; } info operator - (const info &a, const info &b) { info ans; memcpy(ans.al, a.al, sizeof(a.al)); memcpy(ans.ar, b.ar, sizeof(b.ar)); memset(ans.am, 0, sizeof(ans.am)); memset(ans.bl, false, sizeof(ans.bl)); memset(ans.br, false, sizeof(ans.br)); ans.ans = a.ans + b.ans; ans.all = a.all && b.all; ans.arr = false; for (int i = 0; i <= 75; i++) { if (a.br[i + 1]) ans.ans += b.al[i] + b.am[i]; else if (a.all) ans.al[i] += b.al[i], ans.am[i] += b.am[i]; else ans.ar[i] += b.am[i]; ans.al[i] += a.am[i]; ans.bl[i] = a.bl[i]; if (b.all) ans.br[i] = a.br[i] | b.br[i]; else ans.br[i] = b.br[i]; } return ans; } info unita(int val) { info ans; memset(ans.al, 0, sizeof(ans.al)); memset(ans.ar, 0, sizeof(ans.ar)); memset(ans.bl, 0, sizeof(ans.bl)); memset(ans.br, 0, sizeof(ans.br)); memset(ans.am, 0, sizeof(ans.am)); ans.am[val]++; ans.ans = 0; ans.all = ans.arr = true; return ans; } info unitb(int val) { info ans; memset(ans.al, 0, sizeof(ans.al)); memset(ans.ar, 0, sizeof(ans.ar)); memset(ans.bl, 0, sizeof(ans.bl)); memset(ans.br, 0, sizeof(ans.br)); memset(ans.am, 0, sizeof(ans.am)); for (int i = 0; i <= val; i++) ans.bl[i] = ans.br[i] = true; ans.ans = 0; ans.all = ans.arr = true; return ans; } info unit(int pos) { if (type[pos] == 'A') return unita(val[pos]); else return unitb(val[pos]); } struct SegmentTree { struct Node { int lc, rc, home; bool tag; } a[MAXN * 2]; info inf[MAXN], rev[MAXN]; int tot, root, size, n; void update(int root, int mid) { int pos = a[root].home, lc = a[root].lc, rc = a[root].rc; bool tmp = edge.query(mid); if (tmp) { inf[pos] = (a[lc].home ? inf[a[lc].home] : unit(mid)) - (a[rc].home ? inf[a[rc].home] : unit(mid + 1)); rev[pos] = (a[lc].home ? rev[a[lc].home] : unit(mid)) + (a[rc].home ? rev[a[rc].home] : unit(mid + 1)); } else { inf[pos] = (a[lc].home ? inf[a[lc].home] : unit(mid)) + (a[rc].home ? inf[a[rc].home] : unit(mid + 1)); rev[pos] = (a[lc].home ? rev[a[lc].home] : unit(mid)) - (a[rc].home ? rev[a[rc].home] : unit(mid + 1)); } } void pushdown(int root) { if (a[root].tag) { int tmp = a[root].lc; if (a[tmp].home) swap(inf[a[tmp].home], rev[a[tmp].home]); a[tmp].tag ^= true; tmp = a[root].rc; if (a[tmp].home) swap(inf[a[tmp].home], rev[a[tmp].home]); a[tmp].tag ^= true; a[root].tag = false; } } void build(int &root, int l, int r) { root = ++size; if (l == r) return; a[root].home = ++tot; int mid = (l + r) / 2; build(a[root].lc, l, mid); build(a[root].rc, mid + 1, r); update(root, mid); } void init(int x) { n = x; root = size = 0; build(root, 1, n); } void modify(int root, int l, int r, int pos, int d) { if (l == r) { val[l] = d; return; } pushdown(root); int mid = (l + r) / 2; if (mid >= pos) modify(a[root].lc, l, mid, pos, d); else modify(a[root].rc, mid + 1, r, pos, d); update(root, mid); } void modify(int pos, int val) { modify(root, 1, n, pos, val); } void reverse(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) { a[root].tag ^= true; if (a[root].home) swap(inf[a[root].home], rev[a[root].home]); return; } pushdown(root); int mid = (l + r) / 2; if (mid >= ql) reverse(a[root].lc, l, mid, ql, min(mid, qr)); if (mid + 1 <= qr) reverse(a[root].rc, mid + 1, r, max(mid + 1, ql), qr); update(root, mid); } void reverse(int l, int r) { edge.modify(l, r); reverse(root, 1, n, l, r); } } ST; int main() { read(n), read(m); edge.init(n); for (int i = 1; i <= n; i++) { read(val[i]); type[i] = getchar(); while (type[i] != 'A' && type[i] != 'B') type[i] = getchar(); } ST.init(n); while (m--) { static char s[15]; int x, y; scanf("\n%s%d%d", s, &x, &y); if (s[0] == 'U') ST.modify(x, y); else ST.reverse(x, y); if (n == 1) writeln(0); else writeln(ST.inf[ST.a[ST.root].home].ans); } return 0; }