这道题的难处就在于快速对两个“数”进行比较,若能快速对两个“数”进行比较,查询操作用线段树维护即可。
陈立杰13年论文《重量平衡树和后缀平衡树在信息学奥赛中的应用》提到了一种用重量平衡树维护一个序列的方法。
平衡树上每个节点代表一个实数区间,若一个节点代表的区间为 $(l,r)$, 则其左儿子所代表的区间为 $(l, \dfrac{l+r}{2})$,右儿子所代表的区间为 $(\dfrac{l+r}{2}, r)$。而每个节点的值定义为 $\dfrac{l+r}{2}$,这样就能快速比较两个节点的值。而使用重量平衡树重构时对于这部分编码没有额外消耗,所以均摊复杂度仍为期望 $O(\log n)$。
修改操作即为产生一个新的“数”,在平衡树上插入,并对线段树对应节点进行修改。
#includeusing db = double; namespace IO { const int bufl = 1 << 15; char buf[bufl], *s = buf, *t = buf; inline int fetch() { if (s == t) {t = (s = buf) + fread(buf, 1, bufl, stdin); if (s == t)return EOF;} return *s++; } inline int read_i() { int a = 0, b = 1, c = fetch(); while (!isdigit(c))b ^= c == '-', c = fetch(); while (isdigit(c))a = a * 10 + c - 48, c = fetch(); return b ? a : -a; } inline int read_c() { int c = fetch(); while (c <= 32 && c != EOF)c = fetch(); return c; } } using namespace IO; const int N = 5e5 + 7; const db alpha = 0.75; db f[N]; struct Node { int l, r; Node(int _ = 0, int __ = 0): l(_), r(__) {} bool operator < (const Node &p) const { if (f[l] == f[p.l]) return f[r] < f[p.r]; return f[l] < f[p.l]; } bool operator == (const Node &p) const { return f[l] == f[p.l] && f[r] == f[p.r]; } }; int root, highest, n, m; struct Tzy { Node a[N]; int sz[N], ch[N][2], tol; int newnode(Node p) { sz[++tol] = 1; a[tol] = p; return tol; } inline void pushup(int x) { sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; } std::vector<int> vec; void dfs(int x) { if (!x) return; dfs(ch[x][0]); vec.push_back(x); dfs(ch[x][1]); } void build(int &x, int l, int r, db fl, db fr) { if (l > r) { x = 0; return; } int mid = l + r >> 1; db m = (fl + fr) * 0.5; x = vec[mid]; f[x] = m; build(ch[x][0], l, mid - 1, fl, m); build(ch[x][1], mid + 1, r, m, fr); pushup(x); } void rebuild(int &u, db l, db r) { vec.clear(); dfs(u); build(u, 0, vec.size() - 1, l, r); } int insert(int &x, Node p, db fl, db fr) { db m = (fl + fr) * 0.5; if (!x) { x = newnode(p); f[x] = m; return x; } int cur; if (p == a[x]) { cur = x; } else { sz[x]++; if (p < a[x]) cur = insert(ch[x][0], p, fl, m); else cur = insert(ch[x][1], p, m, fr); } if ((db)(sz[x] * alpha) < (db)(std::max(sz[ch[x][0]], sz[ch[x][1]]))) { highest = x; } else { if (highest) { if (highest == ch[x][0]) rebuild(ch[x][0], fl, m); else rebuild(ch[x][1], m, fr); highest = 0; } } return cur; } } tzy; int pos[N]; struct Seg { #define lp p << 1 #define rp p << 1 | 1 int tree[N << 2]; inline int max(int a, int b) { if (f[pos[a]] >= f[pos[b]]) return a; return b; } inline void pushup(int p) { tree[p] = max(tree[lp], tree[rp]); } inline void update(int p, int l, int r, int pos) { if (l == r) { tree[p] = l; return; } int mid = l + r >> 1; if (pos <= mid) update(lp, l, mid, pos); else update(rp, mid + 1, r, pos); pushup(p); } inline int query(int p, int l, int r, int x, int y) { if (x <= l && y >= r) return tree[p]; int mid = l + r >> 1; int ans = 0; if (x <= mid) ans = max(ans, query(lp, l, mid, x, y)); if (y > mid) ans = max(ans, query(rp, mid + 1, r, x, y)); return ans; } void build(int p, int l, int r) { if (l == r) { tree[p] = l; return; } int mid = l + r >> 1; build(lp, l, mid); build(rp, mid + 1, r); pushup(p); } } seg; int main() { n = read_i(), m = read_i(); tzy.insert(root, Node(0, 0), 0, 1); f[0] = -1; for (int i = 1; i <= n; i++) pos[i] = 1; seg.build(1, 1, n); for (int l, r, k; m--; ) { char ch = read_c(); l = read_i(), r = read_i(); if (ch == 'C') { k = read_i(); highest = 0; pos[k] = tzy.insert(root, Node(pos[l], pos[r]), 0, 1); if (highest) tzy.rebuild(root, 0, 1); seg.update(1, 1, n, k); } else { printf("%d\n", seg.query(1, 1, n, l, r)); } } return 0; }