http://www.lydsy.com/JudgeOnline/problem.php?id=3600
php
區間操做是線段樹無疑,難點在於如何考慮這些數對的大小關係.html
咱們考慮一下平衡樹,若是在平衡樹中每一個節點放一個數對,咱們規定中序遍歷前面的數對大於後面的,那麼對於任意一個新數對(x,y)插入時只需知道x,y與每一個節點的數對的關係,就能夠在log的時間內放入.ui
對於x,y與某節點數對的關係,首先要知道x,y必定在平衡樹中存在(不然怎麼被用來構成新數對?),所以能夠log查找x/y與該節點中序遍歷的前後關係來肯定大小關係.spa
可是這樣查找log,插入log,總複雜度達到了log^2,完美爆炸,因此咱們得考慮在O(1)時間內求出(x,y)與某點對的大小關係.code
而後這裏就要用標號的思想了,具體能夠參考CLJ的論文
,對於平衡樹的每個節點使他們表示一個區間,root表示(0,1),左孩子是(0,mid),右孩子是(mid,1),以此類推,(注意一下精度問題, 雖然這題不卡精度, 但我仍是按題解用了(1,long long))節點再記錄一下區間中值做爲編號,而後咱們發現這個編號和中序遍歷是一致的,能夠在O(1)時間內算出兩個數在平衡樹中的前後關係.htm
注意咱們上文中說的x,y都是本身給點對標的號,這些細節就要本身細細地想啦.ci
(論文中有講要用重量平衡樹的理由等等...)get
細節見代碼.
string
#include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <ctime> #include <cstdlib> #define pii pair<int, int> #define mp make_pair #define ft first #define sd second #define ls C[rt][0] #define rs C[rt][1] using namespace std; template <typename ty> void read(ty &x) { x = 0; int f = 1; char ch = getchar(); while (ch > '9' || ch < '0') { if (ch == '-') f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x*10 + ch - '0'; ch = getchar(); } x *= f; } template <typename ty> ty Max(ty a, ty b) { return a > b ? a : b; } template <typename ty> ty Min(ty a, ty b) { return a < b ? a : b; } template <typename ty> int Chkmin(ty &a, ty b) { return a > b ? a = b, 1 : 0; } template <typename ty> int Chkmax(ty &a, ty b) { return a < b ? a = b, 1 : 0; } typedef long long LL; typedef double db; const int inf = 0x7fffffff; const int M = 5e5 + 16; const int N = 1e5 + 16; const db alpha = 0.76; const LL MAXN = (1LL << 62) - 1; //scapegoat_tree LL V[M], L[M], R[M]; int C[M][2], F[M], S[M], A[M], B[M]; // A,B表示點對的先後兩個點在替罪羊樹中的編號 // 注意給0這個(僞)點對的A,B初始化爲<1便可,由於點對都是由兩個書中的點(序號大於0)構成的 //segment_tree int D[N], T[N << 2]; // D表示數列中的點對應的點對在替罪羊樹中的編號 // T表示線段樹中區間的答案(指向一個原數列中的數) int CUR[M]; int root, sz, n, m, l, r, k, tot; int ans, num, mpt; char CH[10]; bool blc(int rt) { return (db) S[rt] * alpha >= (db) S[ls] && (db) S[rt] * alpha >= (db) S[rs]; } void init() { root = sz = 1; V[sz] = (1 + MAXN) >> 1; L[sz] = 1, R[sz] = MAXN; A[sz] = 0, B[sz] = 0; } void recycle(int rt) { if (!rt) return; recycle(ls); CUR[++tot] = rt; recycle(rs); } int build(int l, int r, LL x, LL y) { if (l > r) return 0; int mid = l + r >> 1, now = CUR[mid]; L[now] = x, R[now] = y, V[now] = (x + y) >> 1; F[C[now][0] = build(l, mid - 1, x, V[now])] = now; F[C[now][1] = build(mid + 1, r, V[now], y)] = now; S[now] = S[C[now][0]] + S[C[now][1]] + 1; return now; } void rebuild(int rt) { LL l = L[rt], r = R[rt]; int fa = F[rt], a = (C[fa][1] == rt); tot = 0; recycle(rt); int tmp = build(1, tot, l, r); if (root == rt) root = tmp; F[C[fa][a] = tmp] = fa; } int ins(int &rt, int pre, int x, int y) { if (!rt) { rt = ++ sz; A[sz] = x, B[sz] = y; S[sz] = 1; if (C[pre][0] == rt) L[sz] = L[pre], R[sz] = V[pre]; else L[sz] = V[pre], R[sz] = R[pre]; V[sz] = L[sz] + R[sz] >> 1; F[rt] = pre; return sz; } if (x == A[rt] && y == B[rt]) return rt; int tmp; if (V[x] > V[A[rt]] || (x == A[rt] && V[y] > V[B[rt]])) tmp = ins(C[rt][1], rt, x, y); else tmp = ins(C[rt][0], rt, x, y); S[rt] = S[ls] + S[rs] + 1; if (!blc(rt)) mpt = rt; return tmp; } int insert(int x, int y) { mpt = 0; int ans = ins(root, 0, x, y); if (mpt) rebuild(mpt); return ans; } void build(int rt, int l, int r) { if (l == r) { T[rt] = l; return; } int mid = l + r >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1, r); T[rt] = T[rt << 1]; } int get_max(int a, int b) { int aa = A[D[a]], ab = A[D[b]]; if (V[aa] < V[ab]) return b; if (V[aa] == V[ab] && V[B[D[a]]] < V[B[D[b]]]) return b; return a; } void modify(int rt, int l, int r, int p) { if (l == r) return; int mid = l + r >> 1; if (p <= mid) modify(rt << 1, l, mid, p); else modify(rt << 1 | 1, mid + 1, r, p); T[rt] = get_max(T[rt << 1], T[rt << 1 | 1]); } int query(int rt, int l, int r, int x, int y) { if (x <= l && r <= y) return T[rt]; int mid = l + r >> 1; int a = 0, b = 0; if (x <= mid) a = query(rt << 1, l, mid, x, y); if (y > mid) b = query(rt << 1 | 1, mid + 1, r, x, y); if (!a || !b) return a + b; else return get_max(a, b); } int main () { read(n); read(m); init(); for (int i = 1; i <= n; ++ i) D[i] = 1; build(1, 1, n); while (m --) { scanf("%s", CH); read(l); read(r); if (CH[0] == 'C') { read(k); D[k] = insert(D[l], D[r]); modify(1, 1, n, k); } else printf("%d\n", query(1, 1, n, l, r)); } return 0; }