//一维树状数组 //单点修改 + 单点查询 + 区间修改 + 区间查询 + 区间最值 int n; template struct BIT { T A[N]; //T B[N]; //区间增减/维护最值 int lowbit(int x) { return x & -x; } void init() { memset(A, 0, sizeof(A)); /*memset(B, 0, sizeof(B));*/ } void update(int i, T v) { while (i <= n) { A[i] += v; i += lowbit(i); } } T query(int i) { T ret = 0; while (i) { ret += A[i]; i -= lowbit(i); } return ret; } T query(int i, int j) { return query(j) - query(i - 1); } //区间修改 T query(int x) { if (!x) { return 0; } T ret1 = 0, ret2 = 0; for (int i = x; i <= n; i += lowbit(i)) { ret1 += A[i]; } for (int i = x - 1; i > 0; i -= lowbit(i)) { ret2 += B[i]; } return ret1 * x + ret2; } void update(int x, T v) { for (int i = x; i > 0; i -= lowbit(i)) { A[i] += v; } for (int i = x; i <= n; i += lowbit(i)) { B[i] += x * v; } } void update(int i, int j, T v) { update(j, v); if (i > 1) { update(i - 1, -v); } } //维护区间最值 O(log^2(n)) void modify(int x, T v) { B[x] = v; for (int i = x; i <= n; i += lowbit(i)) { A[i] = max(A[i], v); for (int j = 1; j < lowbit(i); j <<= 1) { A[i] = max(A[i], A[i - j]); } } } T query(int l, int r) { T ret = B[r]; while (true) { ret = max(ret, B[r]); if (l == r) { break; } for (r -= 1; r - l >= lowbit(r); r -= lowbit(r)) { ret = max(ret, A[r]); } } return ret; } //求区间第K大的下标/值 O(log^2(n)) int getK(int l, int r, int k) { while (l <= r) { int mid = l + ((r - l) >> 1); if (query(mid) >= k) { r = mid - 1; } else { l = mid + 1; } } return l; //A[l] } }; BIT bit; //二维树状数组 //单点修改 + 单点查询 + 区域修改 + 区域查询 int n, m; template struct BIT { T A[N][N]; //T B[N][N], C[N][N], D[N][N]; //区域求和 int lowbit(int x) { return x & -x; } void init() { memset(A, 0, sizeof(A)); /*memset(B, 0, sizeof(B)); memset(C, 0, sizeof(C)); memset(D, 0, sizeof(D));*/ } T get(int x, int y) { T ret = 0; for (int i = x; i > 0; i -= lowbit(i)) { for (int j = y; j > 0; j -= lowbit(j)) { ret += A[i][j]; } } return ret; } T query(int x, int y) { return get(x, y) - get(x, y - 1) - get(x - 1, y) + get(x - 1, y - 1); } void update(int x, int y, T v) { for (int i = x; i <= n; i += lowbit(i)) { for (int j = y; j <= m; j += lowbit(j)) { A[i][j] += v; } } } //区域和[x1][y1]-[x2][y2] T query(int x1, int y1, int x2, int y2) { return get(x2, y2) - get(x1 - 1, y2) - get(x2, y1 - 1) + get(x1 - 1, y1 - 1); } //区域增减 void update(int x, int y, T v, T a[][N]) { for (int i = x; i <= n; i += lowbit(i)) { for (int j = y; j <= m; j += lowbit(j)) { a[i][j] += v; } } } void update(int x1, int y1, int x2, int y2, T v) { update(x1, y1, v, A); update(x2 + 1, y1, -v, A); update(x1, y2 + 1, -v, A); update(x2 + 1, y2 + 1, v, A); update(x1, y1, v * x1, B); update(x2 + 1, y1, -v * (x2 + 1), B); update(x1, y2 + 1, -v * x1, B); update(x2 + 1, y2 + 1, v * (x2 + 1), B); update(x1, y1, v * y1, C); update(x2 + 1, y1, -v * y1, C); update(x1, y2 + 1, -v * (y2 + 1), C); update(x2 + 1, y2 + 1, v * (y2 + 1), C); update(x1, y1, v * x1 * y1, D); update(x2 + 1, y1, -v * (x2 + 1) * y1, D); update(x1, y2 + 1, -v * x1 * (y2 + 1), D); update(x2 + 1, y2 + 1, v * (x2 + 1) * (y2 + 1), D); } }; BIT bit; //线段树 单点修改 + 区间查询 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 template struct SegmentTree { T data[N << 2]; T calc(const T &x, const T &y)const { return x + y; } void push_up(int rt) { data[rt] = calc(data[rt << 1], data[rt << 1 | 1]); } void build(int l, int r, int rt) { if (l == r) { scanf("%d", &data[rt]); return; } int m = (l + r) >> 1; build(lson); build(rson); push_up(rt); } void update(int p, T val, int l, int r, int rt) { if (l == r) { data[rt] += val; return; } int m = (l + r) >> 1; if (p <= m) { update(p, val, lson); } else { update(p, val, rson); } push_up(rt); } T query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return data[rt]; } int m = (l + r) >> 1; T ret = 0; if (L <= m) { ret = calc(ret, query(L, R, lson)); } if (m < R) { ret = calc(ret, query(L, R, rson)); } return ret; } }; SegmentTree st; //线段树 区间查询/修改 + 延迟标记 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 template struct SegmentTree { T data[N << 2], lazy[N << 2]; T calc(const T &x, const T &y)const { return x + y; } void push_up(int rt) { data[rt] = calc(data[rt << 1], data[rt << 1 | 1]); } void push_down(int rt, int len) { if (lazy[rt]) { data[rt << 1] += lazy[rt] * (len - (len >> 1)); lazy[rt << 1] += lazy[rt]; data[rt << 1 | 1] += lazy[rt] * (len >> 1); lazy[rt << 1 | 1] += lazy[rt]; lazy[rt] = 0; } } void build(int l, int r, int rt) { lazy[rt] = 0; if (l == r) { scanf("%d", &data[rt]); return; } int m = (l + r) >> 1; build(lson); build(rson); push_up(rt); } void update(int L, int R, T val, int l, int r, int rt) { if (L <= l && r <= R) { data[rt] += val * (r - l + 1); lazy[rt] += val; return; } push_down(rt, r - l + 1); int m = (l + r) >> 1; if (L <= m) { update(L, R, val, lson); } if (m < R) { update(L, R, val, rson); } push_up(rt); } T query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return data[rt]; } push_down(rt, r - l + 1); int m = (l + r) >> 1; T ret = 0; if (L <= m) { ret = calc(ret, query(L, R, lson)); } if (m < R) { ret = calc(ret, query(L, R, rson)); } return ret; } }; SegmentTree st; //非递归版线段树 单点修改 + 区间查询 const int N = ((131072 << 1) + 10); //节点个数->不小于区间长度+2的最小2的正整数次幂*2+10 #define l(x) ((x)<<1) //x的左儿子 #define r(x) (((x)<<1)|1) //x的右儿子 template struct zkwSegmentTree { int m; //底层节点数 T sum[N]; //区间和 void build(int n) { for (m = 1; m < n + 2; m <<= 1); for (int i = 1; i <= n; i++) { scanf("%d", &sum[m + i]); } for (int i = m - 1; i; i--) { sum[i] = sum[l(i)] + sum[r(i)]; } } void update(int p, T val) { for (sum[p += m] += val, p >>= 1; p; p >>= 1) { sum[p] = sum[l(p)] + sum[r(p)]; } } T query(int l, int r) { T ret = 0; for (l += m - 1, r += m + 1; l ^ r ^ 1; l >>= 1, r >>= 1) { if (~l & 1) { ret += sum[l ^ 1]; } if (r & 1) { ret += sum[r ^ 1]; } } return ret; } }; zkwSegmentTree st; //非递归版线段树 区间查询/修改 + 延迟标记 const int N = ((131072 << 1) + 10); //节点个数->不小于区间长度+2的最小2的正整数次幂*2+10 #define l(x) ((x)<<1) //x的左儿子 #define r(x) (((x)<<1)|1) //x的右儿子 template struct zkwSegmentTree { int m, h; //底层节点数 高度 T sum[N], add[N]; //区间和 延迟标记 void pushdown(int rt) { for (int i = h, p; i; i--) { //自顶向下 if (add[p = rt >> i]) { add[p] >>= 1; //add[p]为节点增加总量, 子节点增加一半 sum[l(p)] += add[p]; add[l(p)] += add[p]; sum[r(p)] += add[p]; add[r(p)] += add[p]; add[p] = 0; } } } void build(int n) { for (m = 1, h = 0; m < n + 2; m <<= 1, h++); for (int i = 1; i <= n; i++) { scanf("%d", &sum[m + i]); } for (int i = m - 1; i; i--) { sum[i] = sum[l(i)] + sum[r(i)]; } } void update(int l, int r, T val) { l += m - 1, r += m + 1; int ll = l >> 1, rr = r >> 1; for (pushdown(l), pushdown(r); l ^ r ^ 1; l >>= 1, r >>= 1, val <<= 1) { if (~l & 1) { sum[l ^ 1] += val; add[l ^ 1] += val; } if (r & 1) { sum[r ^ 1] += val; add[r ^ 1] += val; } } for (; ll; ll >>= 1) { sum[ll] = sum[l(ll)] + sum[r(ll)]; } for (; rr; rr >>= 1) { sum[rr] = sum[l(rr)] + sum[r(rr)]; } } T query(int l, int r) { T ret = 0; l += m - 1, r += m + 1; for (pushdown(l), pushdown(r); l ^ r ^ 1; l >>= 1, r >>= 1) { if (~l & 1) { ret += sum[l ^ 1]; } if (r & 1) { ret += sum[r ^ 1]; } } return ret; } }; zkwSegmentTree st; //可持久化线段树 const int N = 100005; const int M = 2500005; const int INF = 0x3f3f3f3f; int n, m, nn; //离散化后大小 #define lson l,m,ls[rt] #define rson m+1,r,rs[rt] template struct SegmentTree { int ls[M], rs[M], root[N], tot; T data[M]; int new_node() { return ++tot; } void build(int l, int r, int &rt) { rt = new_node(); data[rt] = 0; if (l == r) { return; } int m = (l + r) >> 1; build(lson); build(rson); } void update(int p, T val, int lst, int l, int r, int &rt) { rt = new_node(); ls[rt] = ls[lst]; rs[rt] = rs[lst]; data[rt] = data[lst] + val; if (l == r) { return; } int m = (l + r) >> 1; if (p <= m) { update(p, val, ls[lst], lson); } else { update(p, val, rs[lst], rson); } } //带修改区间第k小 int tree[N], use[N]; int lowbit(int x) { return x & -x; } void modify(int x, int p, T val) { //x为原数列中的下标, p为值 for (int i = x; i <= n; i += lowbit(i)) { update(p, val, tree[i], 1, nn, tree[i]); } } T query(int x) { T ret = 0; for (int i = x; i; i -= lowbit(i)) { ret += data[ls[use[i]]]; } return ret; } int query(int L, int R, int k, int l, int r) { for (int i = L; i; i -= lowbit(i)) { use[i] = tree[i]; } for (int i = R; i; i -= lowbit(i)) { use[i] = tree[i]; } int lr = root[L], rr = root[R]; while (l < r) { int m = (l + r) >> 1; T tmp = query(R) - query(L) + data[ls[rr]] - data[ls[lr]]; if (k <= tmp) { r = m; for (int i = L; i; i -= lowbit(i)) { use[i] = ls[use[i]]; } for (int i = R; i; i -= lowbit(i)) { use[i] = ls[use[i]]; } lr = ls[lr]; rr = ls[rr]; } else { l = m + 1; k -= tmp; for (int i = L; i; i -= lowbit(i)) { use[i] = rs[use[i]]; } for (int i = R; i; i -= lowbit(i)) { use[i] = rs[use[i]]; } lr = rs[lr]; rr = rs[rr]; } } return l; } }; SegmentTree st; //ZOJ 2112 int a[N], hs[N], l[N], r[N], k[N]; char op[N]; int main() { int C = 0, T; scanf("%d", &T); while (++C <= T) { nn = 0; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); hs[++nn] = a[i]; } for (int i = 0; i < m; i++) { scanf(" %c%d%d", &op[i], &l[i], &r[i]); switch (op[i]) { case 'Q': scanf("%d", &k[i]); break; case 'C': hs[++nn] = r[i]; break; } } sort(hs + 1, hs + nn + 1); nn = unique(hs + 1, hs + nn + 1) - hs - 1; for (int i = 1; i <= n; ++i) { a[i] = lower_bound(hs + 1, hs + nn + 1, a[i]) - hs; } st.tot = 0; st.build(1, nn, st.root[0]); for (int i = 1; i <= n; i++) { st.update(a[i], 1, st.root[i - 1], 1, nn, st.root[i]); } for (int i = 1; i <= n; i++) { st.tree[i] = st.root[0]; } for (int i = 0; i < m; i++) { switch (op[i]) { case 'Q': printf("%d\n", hs[st.query(l[i] - 1, r[i], k[i], 1, nn)]); break; case 'C': st.modify(l[i], a[l[i]], -1); a[l[i]] = lower_bound(hs + 1, hs + nn + 1, r[i]) - hs; st.modify(l[i], a[l[i]], 1); break; } } } } //实时开节点的权值线段树 (无需离散化) O(logV) const int N = 60005; const int M = 2500005; const int INF = 0x3f3f3f3f; int n, a[N]; #define lson l,m,ls[rt] #define rson m+1,r,rs[rt] struct SegmentTree { int ls[M], rs[M], cnt[M], root[N], tot; void init() { tot = 0; memset(cnt, 0, sizeof(cnt)); memset(root, 0, sizeof(root)); memset(ls, 0, sizeof(ls)); memset(rs, 0, sizeof(rs)); } int new_node() { return ++tot; } void update(int p, int val, int l, int r, int &rt) { if (!rt) { rt = new_node(); } if (l == r) { cnt[rt] += val; return; } int m = (l + r) >> 1; if (p <= m) { update(p, val, lson); } else { update(p, val, rson); } cnt[rt] = cnt[ls[rt]] + cnt[rs[rt]]; } int use[N]; int lowbit(int x) { return x & -x; } //单点修改 void modify(int x, int p, int val) { for (int i = x; i <= n; i += lowbit(i)) { update(p, val, 0, INF, root[i]); } } int query(int x) { int ret = 0; for (int i = x; i; i -= lowbit(i)) { ret += cnt[ls[use[i]]]; } return ret; } //查询区间第k小 int query(int L, int R, int k, int l, int r) { for (int i = L; i; i -= lowbit(i)) { use[i] = root[i]; } for (int i = R; i; i -= lowbit(i)) { use[i] = root[i]; } while (l < r) { int m = (l + r) >> 1, tmp = query(R) - query(L); if (k <= tmp) { r = m; for (int i = L; i; i -= lowbit(i)) { use[i] = ls[use[i]]; } for (int i = R; i; i -= lowbit(i)) { use[i] = ls[use[i]]; } } else { l = m + 1; k -= tmp; for (int i = L; i; i -= lowbit(i)) { use[i] = rs[use[i]]; } for (int i = R; i; i -= lowbit(i)) { use[i] = rs[use[i]]; } } } return l; } } st; //BZOJ1901 区间第k小 int main() { int m, l, r, k; char op[5]; while (~scanf("%d%d", &n, &m)) { st.init(); for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); st.modify(i, a[i], 1); } while (m--) { scanf("%s%d%d", op, &l, &r); switch (op[0]) { case 'Q': scanf("%d", &k); printf("%d\n", st.query(l - 1, r, k, 0, INF)); break; case 'C': st.modify(l, a[l], -1); a[l] = r; st.modify(l, a[l], 1); break; } } } } //平衡二叉树 常用操作 //注意这些操作适用于不允许重复值的平衡二叉树(set而非multiset) //对于允许重复值(拥有cnt域)的实现, 只要在一些+1的地方稍作修改(改成cnt[x])即可 bool find(int v) { for (int x = root; x; x = ch[x][key[x] < v]) { if (key[x] == v) { return true; } } return false; } int getKth(int k) { int x = root; while (size[ch[x][0]] + 1 != k) { if (k < size[ch[x][0]] + 1) { x = ch[x][0]; } else { k -= size[ch[x][0]] + 1; x = ch[x][1]; } } return key[x]; } int getRank(int v) { int ret = 0, x = root; while (x) { if (v < key[x]) { x = ch[x][0]; } else { ret += size[ch[x][0]] + 1; x = ch[x][1]; } } return ret; } int getPre(int v) { int x = root, y = 0; while (x) { if (v < key[x]) { x = ch[x][0]; } else { y = x; x = ch[x][1]; } } return y; } int getNext(int v) { int x = root, y = 0; while (x) { if (v > key[x]) { x = ch[x][1]; } else { y = x; x = ch[x][0]; } } return y; } int getMin() { if (size[root] == 0) { return -1; } int x = root; while (ch[x][0]) { x = ch[x][0]; } return x; } int getMax() { if (size[root] == 0) { return -1; } int x = root; while (ch[x][1]) { x = ch[x][1]; } return x; } //Debug遍历 void treaval(int x) { if (x != 0) { treaval(ch[x][0]); printf("Node%2d:lson %2d rson %2d size = %2d ,val = %2d\n", x, ch[x][0], ch[x][1], size[x], key[x]); treaval(ch[x][1]); } } void debug() { printf("root:%d\n", root); treaval(root); putchar('\n'); } //基于旋转的Treap 允许重复值 //维护序列的有序性和堆的性质, 依靠堆值的随机化, //将树的高度维护在期望下平衡的程度,从而实现了各种操作期望O(logn)的复杂度. //它的性价比高在只有两种旋转(而且可以合并地写), 比红黑树和AVL短小 struct Treap { int tot, root; int ch[N][2], key[N], pt[N], cnt[N], size[N]; void init() { tot = root = 0; pt[0] = INF; } void push_up(int x) { size[x] = size[ch[x][0]] + size[ch[x][1]] + cnt[x]; } void new_node(int &x, int v) { x = ++tot; ch[x][0] = ch[x][1] = 0; size[x] = cnt[x] = 1; pt[x] = rand(); key[x] = v; } void rotate(int &x, int f) { int y = ch[x][f]; ch[x][f] = ch[y][f ^ 1]; ch[y][f ^ 1] = x; push_up(x); push_up(y); x = y; } void insert(int &x, int v) { if (!x) { new_node(x, v); return; } if (key[x] == v) { ++cnt[x]; } else { int f = key[x] < v; insert(ch[x][f], v); if (pt[ch[x][f]] < pt[x]) { rotate(x, f); } } push_up(x); } void erase(int &x, int v) { if (!x) { return; } if (key[x] == v) { if (cnt[x] > 1) { --cnt[x]; } else { if (!ch[x][0] && !ch[x][1]) { x = 0; } else { rotate(x, pt[ch[x][0]] > pt[ch[x][1]]); erase(x, v); } } } else { erase(ch[x][key[x] < v], v); } push_up(x); } void insert(int v) { insert(root, v); } void erase(int v) { erase(root, v); } } treap; //Size Balanced Tree 不允许重复值 //独特的平摊时间O(1)的Maintain操作, 具有仅次于红黑树的优秀的时间效率 struct SBT { int root, tot; int ch[N][2], key[N], size[N]; void init() { tot = root = 0; size[0] = 0; } void rotate(int &x, int f) { int y = ch[x][f]; ch[x][f] = ch[y][f ^ 1]; ch[y][f ^ 1] = x; size[y] = size[x]; size[x] = size[ch[x][0]] + size[ch[x][1]] + 1; x = y; } void maintain(int &x, int f) { if (size[ch[ch[x][f]][f]] > size[ch[x][f ^ 1]]) { rotate(x, f); } else if (size[ch[ch[x][f]][f ^ 1]] > size[ch[x][f ^ 1]]) { rotate(ch[x][f], f ^ 1); rotate(x, f); } else { return; } maintain(ch[x][0], 0); maintain(ch[x][1], 1); maintain(x, 0); maintain(x, 1); } void insert(int &x, int v) { if (!x) { x = ++tot; ch[x][0] = ch[x][1] = 0; size[x] = 1; key[x] = v; } else { ++size[x]; insert(ch[x][key[x] < v], v); maintain(x, key[x] < v); } } int erase(int &x, int v) { if (!x) { return 0; } --size[x]; if (key[x] == v || (key[x] > v && !ch[x][0]) || (key[x] < v && !ch[x][1])) { int ret = key[x]; if (ch[x][0] && ch[x][1]) { key[x] = erase(ch[x][0], v + 1); } else { x = ch[x][0] + ch[x][1]; } return ret; } return erase(ch[x][key[x] < v], v); } void insert(int v) { insert(root, v); } void erase(int v) { erase(root, v); } } sbt; //Splay //可以实现很多其它平衡树无法实现的操作(如区间翻转), 既可以维护集合信息, //也可以维护序列信息, 可以用它来做Treap的题, 也可以用它来做线段树的题. //更重要的是, Splay可以实现split(将某棵子树从原树中分离)和merge操作(将某棵子树插入另一棵树), //这也使得区间插入删除成为可能. 它的美中不足是常数稍大, 约是Treap的1.5~3倍, 线段树的2~5倍. //Splay有单旋和双旋两种实现, 其中只有双旋保证了均摊O(logn)的单次操作复杂度, //但因为很多人认为zigzag太长不好敲(大多是OI选手有此困扰), 选择了单旋. //其实完全可以稍微损失一点常数, 合并成一个rotate函数来完成双旋. //此外一个良好的实现通常要在序列一首一尾增加两个哨兵节点, 这样可以减少很多边界特判. //有必要进行的扩展性说明是, 对于一棵树, 如果想要维护子树信息, 我们可以用Splay维护这棵树的括号序列(dfs序), //这样便可以轻易split出任意子树所属的区间;而用Splay维护dfs序的结构, 就是Euler-Tour Tree. //同样的, 如果想要维护链上信息, 可以先树链剖分然后用Splay维护每条重链, //根据杨哲在07年国家集训队作业的计算, 因其势能分析得到的复杂度依然是单次操作均摊O(logn)复杂度; //而类似的思想做些转化, 就变成了后面会提到的Link-Cut Tree(以下简称LCT). //ver.1 #define keyTree (ch[ch[root][1]][0]) const int N = 200005; const int INF = 0x3f3f3f3f; int num[N]; struct Splay { int root, tot1, tot2; int ch[N][2], pre[N], size[N]; int gc[N], que[N]; int key[N], vmin[N], add[N], rev[N]; void rotate(int x, int f) { int y = pre[x]; ch[y][f ^ 1] = ch[x][f]; pre[ch[x][f]] = y; pre[x] = pre[y]; if (pre[x]) { ch[pre[y]][ch[pre[y]][1] == y] = x; } ch[x][f] = y; pre[y] = x; push_up(y); } void splay(int x, int goal) { push_down(x); while (pre[x] != goal) { int y = pre[x], z = pre[y]; if (z == goal) { push_down(y); push_down(x); rotate(x, ch[y][0] == x); } else { push_down(z); push_down(y); push_down(x); int f = ch[z][0] == y; if (ch[y][f] == x) { rotate(x, f ^ 1); } else { rotate(y, f); } rotate(x, f); } } push_up(x); if (goal == 0) { root = x; } } void rotate_to(int k, int goal) { int x = root; push_down(x); while (size[ch[x][0]] != k) { if (k < size[ch[x][0]]) { x = ch[x][0]; } else { k -= size[ch[x][0]] + 1; x = ch[x][1]; } push_down(x); } splay(x, goal); } void erase(int x) { int fa = pre[x], head = 0, tail = 0; for (que[tail++] = x; head < tail; ++head) { gc[tot2++] = que[head]; if (ch[que[head]][0]) { que[tail++] = ch[que[head]][0]; } if (ch[que[head]][1]) { que[tail++] = ch[que[head]][1]; } } ch[fa][ch[fa][1] == x] = 0; push_up(fa); } void new_node(int &x, int v, int fa) { if (tot2) { x = gc[--tot2]; } else { x = ++tot1; } ch[x][0] = ch[x][1] = 0; pre[x] = fa; size[x] = 1; key[x] = vmin[x] = v; add[x] = rev[x] = 0; } void update_add(int x, int d) { if (x) { key[x] += d; add[x] += d; vmin[x] += d; } } void update_rev(int x) { if (x) { swap(ch[x][0], ch[x][1]); rev[x] ^= 1; } } void push_up(int x) { size[x] = size[ch[x][0]] + size[ch[x][1]] + 1; vmin[x] = min(key[x], min(vmin[ch[x][0]], vmin[ch[x][1]])); } void push_down(int x) { if (add[x]) { update_add(ch[x][0], add[x]); update_add(ch[x][1], add[x]); add[x] = 0; } if (rev[x]) { update_rev(ch[x][0]); update_rev(ch[x][1]); rev[x] = 0; } } void build(int &x, int l, int r, int f) { int m = l + r >> 1; new_node(x, num[m], f); if (l < m) { build(ch[x][0], l, m - 1, x); } if (r > m) { build(ch[x][1], m + 1, r, x); } push_up(x); } void init(int n) { root = tot1 = tot2 = 0; ch[0][0] = ch[0][1] = pre[0] = size[0] = 0; add[0] = rev[0] = 0; key[0] = vmin[0] = INF; new_node(root, -1, 0); new_node(ch[root][1], -1, root); size[root] = 2; for (int i = 1; i <= n; ++i) { scanf("%d", &num[i]); } build(keyTree, 1, n, ch[root][1]); push_up(ch[root][1]); push_up(root); } void plus(int l, int r, int v) { rotate_to(l - 1, 0); rotate_to(r + 1, root); update_add(keyTree, v); } void reverse(int l, int r) { rotate_to(l - 1, 0); rotate_to(r + 1, root); update_rev(keyTree); } void revolve(int l, int r, int k) { k %= r - l + 1; if (!k) { return; } rotate_to(r - k, 0); rotate_to(r + 1, root); int tmp = keyTree; keyTree = 0; push_up(ch[root][1]); push_up(root); rotate_to(l - 1, 0); rotate_to(l, root); keyTree = tmp; pre[tmp] = ch[root][1]; push_up(ch[root][1]); push_up(root); } void insert(int k, int v) { rotate_to(k, 0); rotate_to(k + 1, root); new_node(keyTree, v, ch[root][1]); push_up(ch[root][1]); push_up(root); } void del(int k) { rotate_to(k - 1, 0); rotate_to(k + 1, root); erase(keyTree); push_up(ch[root][1]); push_up(root); } int query(int l, int r) { rotate_to(l - 1, 0); rotate_to(r + 1, root); return vmin[keyTree]; } } splay; int main() { int n, m, x, y, v; char op[10]; while (~scanf("%d", &n)) { splay.init(n); scanf("%d", &m); while (m--) { scanf("%s", op); switch (op[0]) { case 'A': scanf("%d%d%d", &x, &y, &v); splay.plus(x, y, v); break; case 'R': scanf("%d%d", &x, &y); if (op[3] == 'E') { splay.reverse(x, y); } else { scanf("%d", &v); splay.revolve(x, y, v); } break; case 'I': scanf("%d%d", &x, &v); splay.insert(x, v); break; case 'D': scanf("%d", &x); splay.del(x); break; case 'M': scanf("%d%d", &x, &y); printf("%d\n", splay.query(x, y)); break; } } } } //ver.2 int k1, k2, num[N]; struct Splay { int root, tot, point; int ch[N][2], pre[N], size[N]; int key[N], add[N], rev[N]; bool isroot(int x) { return !pre[x] || ch[pre[x]][0] != x && ch[pre[x]][1] != x; } void rotate(int x) { int y = pre[x], f = ch[y][1] == x; ch[y][f] = ch[x][f ^ 1]; pre[ch[y][f]] = y; if (!isroot(y)) { ch[pre[y]][ch[pre[y]][1] == y] = x; } pre[x] = pre[y]; ch[x][f ^ 1] = y; pre[y] = x; push_up(y); } void splay(int x) { push_down(x); while (!isroot(x)) { int y = pre[x], z = pre[y]; if (isroot(y)) { push_down(y); push_down(x); rotate(x); } else { push_down(z); push_down(y); push_down(x); rotate((ch[z][1] == y) == (ch[y][1] == x) ? y : x); rotate(x); } } push_up(x); } void new_node(int &x, int v, int fa) { x = ++tot; ch[x][0] = ch[x][1] = 0; pre[x] = fa; size[x] = 1; key[x] = v; add[x] = rev[x] = 0; } void update_add(int x, int v) { if (x) { key[x] += v; add[x] += v; } } void update_rev(int x) { if (x) { rev[x] ^= 1; swap(ch[x][0], ch[x][1]); } } void push_down(int x) { if (add[x]) { update_add(ch[x][0], add[x]); update_add(ch[x][1], add[x]); add[x] = 0; } if (rev[x]) { update_rev(ch[x][0]); update_rev(ch[x][1]); rev[x] = 0; } } void push_up(int x) { size[x] = size[ch[x][0]] + size[ch[x][1]] + 1; } void build(int &x, int l, int r, int fa) { int m = l + r >> 1; new_node(x, num[m], fa); if (l < m) { build(ch[x][0], l, m - 1, x); } if (r > m) { build(ch[x][1], m + 1, r, x); } push_up(x); } void init(int n) { root = tot = size[0] = 0; for (int i = 1; i <= n; ++i) { scanf("%d", &num[i]); } build(root, 1, n, 0); point = 1; } int find(int rt, int k) { int x = rt; while (size[ch[x][0]] + 1 != k) { push_down(x); if (k <= size[ch[x][0]]) { x = ch[x][0]; } else { k -= size[ch[x][0]] + 1; x = ch[x][1]; } } return x; } void split(int &x, int &y, int sz) { if (!sz) { y = x; x = 0; return; } y = find(x, sz + 1); splay(y); x = ch[y][0]; ch[y][0] = 0; push_up(y); } void split3(int &x, int &y, int &z, int l, int r) { split(x, z, r); split(x, y, l - 1); } void join(int &x, int &y) { if (!x || !y) { x |= y; return; } x = find(x, size[x]); splay(x); ch[x][1] = y; pre[y] = x; push_up(x); } void join3(int &x, int y, int z) { join(y, z); join(x, y); } void evert() { if (point > 1) { int x; split(root, x, point - 1); swap(root, x); join(root, x); point = 1; } } void plus(int v) { evert(); int x, y; split3(root, x, y, point, point + k2 - 1); update_add(x, v); join3(root, x, y); } void reverse() { evert(); int x, y; split3(root, x, y, point, point + k1 - 1); update_rev(x); join3(root, x, y); } void insert(int v) { evert(); int x, y; split(root, x, point); new_node(y, v, 0); join3(root, y, x); } void erase() { evert(); int x, y; split3(root, x, y, point, point); join(root, y); } void move(int tag) { switch (tag) { case 1: if (--point == 0) { point = size[root]; } break; case 2: if (++point == size[root] + 1) { point = 1; } break; } } void query() { evert(); int x, y; split3(root, x, y, point, point); printf("%d\n", key[x]); join3(root, x, y); } } splay; //HDU4453 int main() { int n, m, v, cas = 0; char op[10]; while (~scanf("%d%d%d%d", &n, &m, &k1, &k2) && (n || m || k1 || k2)) { splay.init(n); printf("Case #%d:\n", ++cas); while (m--) { scanf("%s", op); switch (op[0]) { case 'a': scanf("%d", &v); splay.plus(v); break; case 'r': splay.reverse(); break; case 'i': scanf("%d", &v); splay.insert(v); break; case 'd': splay.erase(); break; case 'm': scanf("%d", &v); splay.move(v); break; case 'q': splay.query(); break; } } } } //ver.3 const int N = 500005; const int INF = 0x3f3f3f3f; int n, q; struct Splay { int pre[N], ch[N][2], key[N], size[N]; int root, tot1; int sum[N], rev[N], same[N]; int lx[N], rx[N], mx[N]; int s[N], tot2; //内存池和容量 int a[N]; void NewNode(int &r, int father, int k) { if (tot2) { r = s[tot2--]; } //取的时候是tot2--,存的时候就是++tot2 else { r = ++tot1; } pre[r] = father; ch[r][0] = ch[r][1] = 0; key[r] = k; sum[r] = k; rev[r] = same[r] = 0; lx[r] = rx[r] = mx[r] = k; size[r] = 1; } void Update_Rev(int r) { if (!r) { return; } swap(ch[r][0], ch[r][1]); swap(lx[r], rx[r]); rev[r] ^= 1; } void Update_Same(int r, int v) { if (!r) { return; } key[r] = v; sum[r] = v * size[r]; lx[r] = rx[r] = mx[r] = max(v, v * size[r]); same[r] = 1; } void push_up(int r) { int lson = ch[r][0], rson = ch[r][1]; size[r] = size[lson] + size[rson] + 1; sum[r] = sum[lson] + sum[rson] + key[r]; lx[r] = max(lx[lson], sum[lson] + key[r] + max(0, lx[rson])); rx[r] = max(rx[rson], sum[rson] + key[r] + max(0, rx[lson])); mx[r] = max(0, rx[lson]) + key[r] + max(0, lx[rson]); mx[r] = max(mx[r], max(mx[lson], mx[rson])); } void push_down(int r) { if (same[r]) { Update_Same(ch[r][0], key[r]); Update_Same(ch[r][1], key[r]); same[r] = 0; } if (rev[r]) { Update_Rev(ch[r][0]); Update_Rev(ch[r][1]); rev[r] = 0; } } void Build(int &x, int l, int r, int father) { if (l > r) { return; } int mid = (l + r) / 2; NewNode(x, father, a[mid]); Build(ch[x][0], l, mid - 1, x); Build(ch[x][1], mid + 1, r, x); push_up(x); } void Init() { root = tot1 = tot2 = 0; ch[root][0] = ch[root][1] = size[root] = pre[root] = 0; same[root] = rev[root] = sum[root] = key[root] = 0; lx[root] = rx[root] = mx[root] = -INF; NewNode(root, 0, -1); NewNode(ch[root][1], root, -1); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } Build(ch[ch[root][1]][0], 0, n - 1, ch[root][1]); push_up(ch[root][1]); push_up(root); } //旋转,0为左旋, 1为右旋 void Rotate(int x, int kind) { int y = pre[x]; push_down(y); push_down(x); ch[y][!kind] = ch[x][kind]; pre[ch[x][kind]] = y; if (pre[y]) { ch[pre[y]][ch[pre[y]][1] == y] = x; } pre[x] = pre[y]; ch[x][kind] = y; pre[y] = x; push_up(y); } //Splay调整, 将r结点调整到goal下面 void Splay(int r, int goal) { push_down(r); while (pre[r] != goal) { if (pre[pre[r]] == goal) { push_down(pre[r]); push_down(r); Rotate(r, ch[pre[r]][0] == r); } else { push_down(pre[pre[r]]); push_down(pre[r]); push_down(r); int y = pre[r]; int kind = ch[pre[y]][0] == y; if (ch[y][kind] == r) { Rotate(r, !kind); Rotate(r, kind); } else { Rotate(y, kind); Rotate(r, kind); } } } push_up(r); if (goal == 0) { root = r; } } int Get_kth(int r, int k) { push_down(r); int t = size[ch[r][0]] + 1; if (t == k) { return r; } if (t > k) { return Get_kth(ch[r][0], k); } else { return Get_kth(ch[r][1], k - t); } } //在第pos个数后面插入tot个数 void Insert(int pos, int tot) { for (int i = 0; i < tot; i++) { scanf("%d", &a[i]); } Splay(Get_kth(root, pos + 1), 0); Splay(Get_kth(root, pos + 2), root); Build(ch[ch[root][1]][0], 0, tot - 1, ch[root][1]); push_up(ch[root][1]); push_up(root); } //删除子树 void erase(int r) { if (!r) { return; } s[++tot2] = r; erase(ch[r][0]); erase(ch[r][1]); } //从第pos个数开始连续删除tot个数 void Delete(int pos, int tot) { Splay(Get_kth(root, pos), 0); Splay(Get_kth(root, pos + tot + 1), root); erase(ch[ch[root][1]][0]); pre[ch[ch[root][1]][0]] = 0; ch[ch[root][1]][0] = 0; push_up(ch[root][1]); push_up(root); } //将从第pos个数开始的连续的tot个数修改为c void Make_Same(int pos, int tot, int c) { Splay(Get_kth(root, pos), 0); Splay(Get_kth(root, pos + tot + 1), root); Update_Same(ch[ch[root][1]][0], c); push_up(ch[root][1]); push_up(root); } //将第pos个数开始的连续tot个数进行反转 void Reverse(int pos, int tot) { Splay(Get_kth(root, pos), 0); Splay(Get_kth(root, pos + tot + 1), root); Update_Rev(ch[ch[root][1]][0]); push_up(ch[root][1]); push_up(root); } //得到第pos个数开始的tot个数的和 int Get_Sum(int pos, int tot) { Splay(Get_kth(root, pos), 0); Splay(Get_kth(root, pos + tot + 1), root); return sum[ch[ch[root][1]][0]]; } //得到第pos个数开始的tot个数中最大的子段和 int Get_MaxSum(int pos, int tot) { Splay(Get_kth(root, pos), 0); Splay(Get_kth(root, pos + tot + 1), root); return mx[ch[ch[root][1]][0]]; } void InOrder(int r) { if (!r) { return; } push_down(r); InOrder(ch[r][0]); printf("%d ", key[r]); InOrder(ch[r][1]); } } splay; int main() { while (scanf("%d%d", &n, &q) == 2) { splay.Init(); char op[20]; int x, y, z; while (q--) { scanf("%s", op); if (strcmp(op, "INSERT") == 0) { scanf("%d%d", &x, &y); splay.Insert(x, y); } else if (strcmp(op, "DELETE") == 0) { scanf("%d%d", &x, &y); splay.Delete(x, y); } else if (strcmp(op, "MAKE-SAME") == 0) { scanf("%d%d%d", &x, &y, &z); splay.Make_Same(x, y, z); } else if (strcmp(op, "REVERSE") == 0) { scanf("%d%d", &x, &y); splay.Reverse(x, y); } else if (strcmp(op, "GET-SUM") == 0) { scanf("%d%d", &x, &y); printf("%d\n", splay.Get_Sum(x, y)); } else if (strcmp(op, "MAX-SUM") == 0) { printf("%d\n", splay.Get_MaxSum(1, splay.size[root] - 2)); } } } } //Link-Cut Tree 动态树 //维护多棵树(森林)的形态, 并在O(logn)的时间复杂度内维护链上信息; 但LCT处理子树信息将会非常麻烦. //它的核心操作是access函数, 可以把某个节点到根的路径上所有点按照深度用Splay维护起来, //从而结合evert函数(换跟操作)和splay操作可以实现对链的信息维护. //LCT几乎可以实现除维护子树信息外以上的所有操作, 同时有着优越的理论复杂度, //但实际常数较大, 很多不改变树形态的题用O(logn)的LCT并不比O(log^2n)的树链剖分套线段树更优越 struct LCT { int ch[N][2], pre[N], key[N], rev[N]; int add[N], vmax[N]; bool isroot(int x) { return !pre[x] || ch[pre[x]][0] != x && ch[pre[x]][1] != x; } void rotate(int x) { int y = pre[x], f = ch[y][1] == x; ch[y][f] = ch[x][f ^ 1]; pre[ch[y][f]] = y; if (!isroot(y)) { ch[pre[y]][ch[pre[y]][1] == y] = x; } pre[x] = pre[y]; ch[x][f ^ 1] = y; pre[y] = x; push_up(y); } void splay(int x) { push_down(x); while (!isroot(x)) { int y = pre[x], z = pre[y]; if (isroot(y)) { push_down(y); push_down(x); rotate(x); } else { push_down(z); push_down(y); push_down(x); rotate((ch[z][1] == y) == (ch[y][1] == x) ? y : x); rotate(x); } } push_up(x); } int access(int x) { int y = 0; for (; x; x = pre[x]) { splay(x); ch[x][1] = y; push_up(x); y = x; } return y; } void evert(int x) { rev[access(x)] ^= 1; splay(x); } void push_up(int x) { vmax[x] = max(max(vmax[ch[x][0]], vmax[ch[x][1]]), key[x]); } void push_down(int x) { if (add[x]) { key[x] += add[x]; if (ch[x][0]) { add[ch[x][0]] += add[x]; vmax[ch[x][0]] += add[x]; } if (ch[x][1]) { add[ch[x][1]] += add[x]; vmax[ch[x][1]] += add[x]; } add[x] = 0; } if (rev[x]) { if (ch[x][0]) { rev[ch[x][0]] ^= 1; } if (ch[x][1]) { rev[ch[x][1]] ^= 1; } swap(ch[x][0], ch[x][1]); rev[x] = 0; } } int find_root(int x) { while (pre[x]) { x = pre[x]; } return x; } //如果u,v不在同一颗子树中,则通过在u,v之间连边的方式,连接这两颗子树 void link(int u, int v) { if (find_root(u) == find_root(v)) { puts("-1"); return; } evert(u); pre[u] = v; } //如果u,v在同一颗子树中,且u!=v,则将u视为这颗子树的根以后,切断v与其父亲结点的连接 void cut(int u, int v) { if (u == v || find_root(u) != find_root(v)) { puts("-1"); return; } evert(u); access(v); splay(v); pre[ch[v][0]] = 0; ch[v][0] = 0; push_up(v); } //如果u,v在同一颗子树中,则将u,v之间路径上所有点的点权增加w void update(int u, int v, int w) { if (find_root(u) != find_root(v)) { puts("-1"); return; } evert(u); access(v); splay(v); add[v] += w; vmax[v] += w; push_down(v); } //如果u,v在同一颗子树中, 返回u,v之间路径上点权的最大值 void query(int u, int v) { if (find_root(u) != find_root(v)) { puts("-1"); return; } evert(u); access(v); splay(v); printf("%d\n", vmax[v]); } struct graph { int head[N], to[N << 1], next[N << 1]; int tot; void init() { tot = 0; memset(head, 0xff, sizeof(head)); } void add(int u, int v) { to[tot] = v; next[tot] = head[u]; head[u] = tot++; } } g; void dfs(int u, int fa) { for (int i = g.head[u]; ~i; i = g.next[i]) { int v = g.to[i]; if (v != fa) { dfs(v, u); pre[v] = u; } } } void init(int n) { int m, x, y; g.init(); for (int i = 1; i < n; ++i) { scanf("%d%d", &x, &y); g.add(x, y); g.add(y, x); } memset(ch, 0, sizeof(ch)); memset(pre, 0, sizeof(pre)); memset(rev, 0, sizeof(rev)); memset(add, 0, sizeof(add)); vmax[0] = 0; for (int i = 1; i <= n; ++i) { scanf("%d", &key[i]); vmax[i] = key[i]; } dfs(1, 0); } } lct; //HDU4010 int main() { int n, q, op, x, y, w; while (~scanf("%d", &n)) { lct.init(n); scanf("%d", &q); while (q--) { scanf("%d", &op); switch (op) { case 1: scanf("%d%d", &x, &y); lct.link(x, y); break; case 2: scanf("%d%d", &x, &y); lct.cut(x, y); break; case 3: scanf("%d%d%d", &w, &x, &y); lct.update(x, y, w); break; case 4: scanf("%d%d", &x, &y); lct.query(x, y); break; } } putchar('\n'); } } //不基于旋转的Treap int num[N]; struct Treap { int tot, root; int ch[N][2], pt[N], size[N]; int key[N], vmin[N], add[N], rev[N]; void init() { tot = 0; } void new_node(int &x, int v) { x = ++tot; ch[x][0] = ch[x][1] = 0; size[x] = 1; pt[x] = rand(); key[x] = vmin[x] = v; add[x] = rev[x] = 0; } void merge(int &p, int x, int y) { if (!x || !y) { p = x | y; return; } if (pt[x] < pt[y]) { push_down(x); merge(ch[x][1], ch[x][1], y); p = x; } else { push_down(y); merge(ch[y][0], x, ch[y][0]); p = y; } push_up(p); } void split(int p, int sz, int &x, int &y) { if (!sz) { x = 0; y = p; return; } push_down(p); if (size[ch[p][0]] >= sz) { y = p; split(ch[p][0], sz, x, ch[y][0]); } else { x = p; split(ch[p][1], sz - size[ch[p][0]] - 1, ch[x][1], y); } push_up(p); } void update_add(int x, int v) { if (x) { key[x] += v; add[x] += v; vmin[x] += v; } } void update_rev(int x) { if (x) { swap(ch[x][0], ch[x][1]); rev[x] ^= 1; } } void push_down(int x) { if (add[x]) { update_add(ch[x][0], add[x]); update_add(ch[x][1], add[x]); add[x] = 0; } if (rev[x]) { update_rev(ch[x][0]); update_rev(ch[x][1]); rev[x] = 0; } } void push_up(int x) { size[x] = 1; vmin[x] = key[x]; if (ch[x][0]) { size[x] += size[ch[x][0]]; vmin[x] = min(vmin[x], vmin[ch[x][0]]); } if (ch[x][1]) { size[x] += size[ch[x][1]]; vmin[x] = min(vmin[x], vmin[ch[x][1]]); } } int build(int &x, int l, int r) { int m = l + r >> 1; new_node(x, num[m]); if (l < m) { build(ch[x][0], l, m - 1); } if (r > m) { build(ch[x][1], m + 1, r); } push_up(x); } void plus(int l, int r, int v) { int x, y; split(root, l - 1, root, x); split(x, r - l + 1, x, y); update_add(x, v); merge(x, x, y); merge(root, root, x); } void reverse(int l, int r) { int x, y; split(root, l - 1, root, x); split(x, r - l + 1, x, y); update_rev(x); merge(x, x, y); merge(root, root, x); } void revolve(int l, int r, int k) { int x, y, p, q; k %= r - l + 1; if (!k) { return; } split(root, l - 1, root, x); split(x, r - l + 1, x, y); split(x, r - l + 1 - k, p, q); merge(x, q, p); merge(x, x, y); merge(root, root, x); } void insert(int k, int v) { int x, y; new_node(x, v); split(root, k, root, y); merge(root, root, x); merge(root, root, y); } void erase(int k) { int x, y; split(root, k - 1, root, x); split(x, 1, x, y); merge(root, root, y); } int query(int l, int r) { int x, y, ret; split(root, l - 1, root, x); split(x, r - l + 1, x, y); ret = vmin[x]; merge(x, x, y); merge(root, root, x); return ret; } } treap; //POJ3580 int main() { int n, m, x, y, v; char op[10]; while (~scanf("%d", &n)) { treap.init(); for (int i = 1; i <= n; ++i) { scanf("%d", &num[i]); } treap.build(treap.root, 1, n); scanf("%d", &m); while (m--) { scanf("%s", op); switch (op[0]) { case 'A': scanf("%d%d%d", &x, &y, &v); treap.plus(x, y, v); break; case 'R': scanf("%d%d", &x, &y); if (op[3] == 'E') { treap.reverse(x, y); } else { scanf("%d", &v); treap.revolve(x, y, v); } break; case 'I': scanf("%d%d", &x, &v); treap.insert(x, v); break; case 'D': scanf("%d", &x); treap.erase(x); break; case 'M': scanf("%d%d", &x, &y); printf("%d\n", treap.query(x, y)); break; } } } } //可持久化Treap const int N = 50005; const int M = 5000005; int root[N], vs, d; struct Treap { int tot; int ch[M][2], size[M]; char key[M]; bool hey(int x, int y) { return (ll)rand() * (size[x] + size[y]) < (ll)size[x] * RAND_MAX; } void init() { tot = 0; } void new_node(int &x, char v) { x = ++tot; ch[x][0] = ch[x][1] = 0; size[x] = 1; key[x] = v; } void copy_node(int &x, int y) { if (!y) { x = 0; return; } x = ++tot; ch[x][0] = ch[y][0]; ch[x][1] = ch[y][1]; size[x] = size[y]; key[x] = key[y]; } void merge(int &p, int x, int y) { if (!x || !y) { p = 0; if (x) { copy_node(p, x); } if (y) { copy_node(p, y); } return; } if (hey(x, y)) { copy_node(p, x); merge(ch[p][1], ch[x][1], y); } else { copy_node(p, y); merge(ch[p][0], x, ch[y][0]); } push_up(p); } void split(int p, int sz, int &x, int &y) { if (!sz) { x = 0; copy_node(y, p); return; } if (size[ch[p][0]] >= sz) { copy_node(y, p); split(ch[p][0], sz, x, ch[y][0]); push_up(y); } else { copy_node(x, p); split(ch[p][1], sz - size[ch[p][0]] - 1, ch[x][1], y); push_up(x); } } void push_up(int x) { size[x] = 1; if (ch[x][0]) { size[x] += size[ch[x][0]]; } if (ch[x][1]) { size[x] += size[ch[x][1]]; } } void build(char str[], int &x, int l, int r) { int m = l + r >> 1; new_node(x, str[m]); if (l < m) { build(str, ch[x][0], l, m - 1); } if (r > m) { build(str, ch[x][1], m + 1, r); } push_up(x); } void insert(int k, char str[]) { int x, y, z; build(str, x, 0, strlen(str) - 1); split(root[vs], k, y, z); merge(y, y, x); merge(root[++vs], y, z); } void erase(int k, int sz) { int x, y, z; split(root[vs], k - 1, x, y); split(y, sz, y, z); merge(root[++vs], x, z); } void output(int x) { if (ch[x][0]) { output(ch[x][0]); } putchar(key[x]); d += key[x] == 'c'; if (ch[x][1]) { output(ch[x][1]); } } void output(int v, int k, int sz) { int x, y, z; split(root[v], k - 1, x, y); split(y, sz, y, z); output(y); putchar('\n'); } } treap; //UVa12538 int main() { int n, op, p, c, v; char s[105]; treap.init(); vs = d = 0; scanf("%d", &n); while (n--) { scanf("%d", &op); switch (op) { case 1: scanf("%d%s", &p, s); treap.insert(p - d, s); break; case 2: scanf("%d%d", &p, &c); treap.erase(p - d, c - d); break; case 3: scanf("%d%d%d", &v, &p, &c); treap.output(v - d, p - d, c - d); break; } } } //树链剖分 //轻重链剖分将一棵树划分成至多logn条重链和若干条轻边, 满足每个节点属于一条重链, //从而将树上路径修改转化为至多logn次线性修改, 非常利于套用树状数组、线段树等各类数据结构. //树链剖分的常数很小, 且因着树链剖分的性质, 我们发现越是退化的树(极端情况下成为一条链), //树链剖分的效果越是好(极端情况下甚至是O(1)级的, 因为只有很少的重链), //以至于一些不涉及形态修改的树上路径维护题目, 可以用树链剖分套线段树以O(logn^2)的单次操作复杂度水过, //且实际表现不输于单次操作O(logn)但常数很大的LCT. //常见轻重链剖分的初始化实现是两次dfs的, 但dfs有两个问题, //一是递归调用使得时间稍慢, 二是有些题目有爆栈风险; 所以我抄了bfs实现的很好用的交大板. //需要稍作说明的是, 对于点权修改直接维护即可, 对于边权修改, 常规做法是选定一个根, //将边权下垂到深度更大的节点上; 换言之, 每个点储存的权值是它与它的父节点之间的边权, 根节点上没有权值. int top[N]; //top[p]表示编号为p的路径的顶端节点 int len[N]; //len[p]表示路径p的长度 int belong[N]; //belong[v]表示节点v所属的路径编号 int idx[N]; //idx[v]表示节点v在其路径中的编号, 按深度由深到浅依次标号 int dep[N]; //dep[v]表示节点v的深度 int fa[N]; //fa[v]表示节点v的父亲节点 int size[N]; //size[v]表示以节点v为根的子树的节点个数 int que[N]; bool vis[N]; int n, cnt; //n是点数, 标号从1到n void split() { memset(dep, 0xff, sizeof(dep)); int l = 0, r = 0; que[++r] = 1; dep[1] = 0; fa[1] = -1; while (l < r) { int u = que[++l]; vis[u] = false; for (int i = g.head[u]; ~i; i = g.next[i]) { int v = g.to[i]; if (!~dep[v]) { que[++r] = v; dep[v] = dep[u] + 1; fa[v] = u; } } } cnt = 0; for (int i = n; i > 0; --i) { int u = que[i], p = -1; size[u] = 1; for (int j = g.head[u]; ~j; j = g.next[j]) { int v = g.to[j]; if (vis[v]) { size[u] += size[v]; if (!~p || size[v] > size[p]) { p = v; } } } if (!~p) { idx[u] = len[++cnt] = 1; belong[u] = cnt; top[cnt] = u; } else { belong[u] = belong[p]; idx[u] = ++len[belong[u]]; top[belong[u]] = u; } vis[u] = true; } } int fi[N], cid[N], rank[N]; void getcid() { fi[1] = 1; for (int i = 2; i <= cnt; ++i) { fi[i] = fi[i - 1] + len[i - 1]; } for (int i = 1; i <= n; ++i) { cid[i] = fi[belong[i]] + len[belong[i]] - idx[i]; rank[cid[i]] = i; } } // 路径修改和查询依下面修改 int query(int x, int y) { int ret = 0; while (belong[x] != belong[y]) { if (dep[top[belong[x]]] < dep[top[belong[y]]]) { swap(x, y); } ret = max(ret, query(cid[top[belong[x]]], cid[x], 1, n, 1)); x = fa[top[belong[x]]]; } if (dep[x] > dep[y]) { swap(x, y); } ret = max(ret, query(cid[x], cid[y], 1, n, 1)); /*边权如下 if(x!=y) ret=max(ret,query(cid[x]+1,cid[y],1,n,1)); */ return ret; } //第一次dfs和倍增LCA的dfs部分几乎一致; 所以稍作修改就可以无缝衔接LCA. //第二次dfs对节点的新位置进行了标号(对应bfs的getcid函数), //我们可以发现无论它以怎样的顺序进行dfs(先dfs重儿子再dfs其它子节点), 得到的依旧是这棵树的一个dfs序. //换句话说, 这里处理出的剖分标号, 同时也是dfs序标号. //我们知道每棵子树的节点在dfs序中都是连续的一段, //这样我们就可以同时维护树上路径信息(剖分部分复杂度O(logn))和子树信息(剖分部分复杂度O(1))了. //BZOJ3083 树链剖分套线段树 const int N = 100005; const int maxd = 18; const int INF = 0x7fffffff; struct graph { int head[N], tot; int to[N << 1], next[N << 1]; void init() { tot = 0; memset(head, 0xff, sizeof(head)); } void add(int u, int v) { to[tot] = v; next[tot] = head[u]; head[u] = tot++; } } g; int top[N], son[N]; int dep[N], fa[N][maxd], size[N]; int cid[N], rank[N], cnt; void dfs1(int u) { size[u] = 1; son[u] = -1; for (int i = 1; i < maxd; ++i) { fa[u][i] = fa[fa[u][i - 1]][i - 1]; } for (int i = g.head[u]; ~i; i = g.next[i]) { int v = g.to[i]; if (v != fa[u][0]) { dep[v] = dep[u] + 1; fa[v][0] = u; dfs1(v); size[u] += size[v]; if (!~son[u] || size[v] > size[son[u]]) { son[u] = v; } } } } void dfs2(int u, int tp) { top[u] = tp; cid[u] = ++cnt; rank[cid[u]] = u; if (~son[u]) { dfs2(son[u], tp); } for (int i = g.head[u]; ~i; i = g.next[i]) { int v = g.to[i]; if (v != son[u] && v != fa[u][0]) { dfs2(v, v); } } } void split() { dfs1(1); cnt = 0; dfs2(1, 1); } int lca(int u, int v) { if (dep[u] < dep[v]) { swap(u, v); } int k = dep[u] - dep[v]; for (int i = 0; i < maxd; ++i) { if ((1 << i)&k) { u = fa[u][i]; } } if (u == v) { return u; } for (int i = maxd - 1; i >= 0; --i) { if (fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } } return fa[u][0]; } int n, root, a[N]; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int vmin[N << 2], col[N << 2]; void push_up(int rt) { vmin[rt] = min(vmin[rt << 1], vmin[rt << 1 | 1]); } void push_down(int rt) { if (col[rt]) { col[rt << 1] = col[rt << 1 | 1] = vmin[rt << 1] = vmin[rt << 1 | 1] = col[rt]; col[rt] = 0; } } void build(int l, int r, int rt) { col[rt] = 0; if (l == r) { vmin[rt] = a[rank[l]]; return; } int m = l + r >> 1; build(lson); build(rson); push_up(rt); } void update(int L, int R, int val, int l, int r, int rt) { if (L <= l && r <= R) { col[rt] = vmin[rt] = val; return; } push_down(rt); int m = l + r >> 1; if (L <= m) { update(L, R, val, lson); } if (m < R) { update(L, R, val, rson); } push_up(rt); } int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) { return vmin[rt]; } push_down(rt); int m = l + r >> 1; int ret = INF; if (L <= m) { ret = min(ret, query(L, R, lson)); } if (m < R) { ret = min(ret, query(L, R, rson)); } return ret; } void modify(int x, int y, int d) { while (top[x] != top[y]) { if (dep[top[x]] < dep[top[y]]) { swap(x, y); } update(cid[top[x]], cid[x], d, 1, n, 1); x = fa[top[x]][0]; } if (dep[x] > dep[y]) { swap(x, y); } update(cid[x], cid[y], d, 1, n, 1); } int query(int rt) { if (rt == root) { return query(1, n, 1, n, 1); } int pre = lca(root, rt); if (pre != rt) { return query(cid[rt], cid[rt] + size[rt] - 1, 1, n, 1); } int depth = dep[root] - dep[rt] - 1, tmp = root; for (int i = maxd - 1; i >= 0; --i) { if (depth & (1 << i)) { tmp = fa[tmp][i]; } } return min(query(1, cid[tmp] - 1, 1, n, 1), query(cid[tmp] + size[tmp], n, 1, n, 1)); } int main() { int m, u, v, opt, id; while (~scanf("%d%d", &n, &m)) { g.init(); for (int i = 1; i < n; ++i) { scanf("%d%d", &u, &v); g.add(u, v); g.add(v, u); } for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); } split(); build(1, n, 1); scanf("%d", &root); while (m--) { scanf("%d", &opt); switch (opt) { case 1: scanf("%d", &root); break; case 2: scanf("%d%d%d", &u, &v, &id); modify(u, v, id); break; case 3: scanf("%d", &id); printf("%d\n", query(id)); break; } } } } //KD-Tree //用来维护多维第K近点对距离一类的信息. //在每一维上依次用一个超平面进行空间划分, 将点集比较均匀地分割在各个区域内, //结构上则是一棵二叉树, 且与线段树的形态和构造方法都有些类似. //经过改造的KD-Tree一般可以做到O(logn)的单点插入, 以及O(n^(1-1/D))的询问操作, 其中D是维数, 可见维数越大KD-Tree越慢 //询问距离一个点的前K近点一般需要用一个优先队列进行询问时的维护 //HDU4347 O(n) 不支持点的插入和删除 const int N = 50005; const int INF = ~0U >> 1; const int DIM = 5; #define lson l,m-1,dep+1 #define rson m+1,r,dep+1 int cur, K; struct point { int x[DIM]; bool operator<(const point &oth)const { return x[cur] < oth.x[cur]; } void output() { for (int i = 0; i < K; ++i) { printf("%d%c", x[i], i < K - 1 ? ' ' : '\n'); } } } vec[N], origin[N], pt, ans[10]; inline int sqr(int x) { return x * x; } int dist(const point &a, const point &b) { int ret = 0; for (int i = 0; i < K; ++i) { ret += sqr(a.x[i] - b.x[i]); } return ret; } void build(int l, int r, int dep = 0) { if (l >= r) { return; } int m = l + r >> 1; cur = dep % K; nth_element(vec + l, vec + m, vec + r + 1); build(lson); build(rson); } priority_queue> pq; void query(const point &x, int k, int l, int r, int dep = 0) { if (l > r) { return; } int m = l + r >> 1, cur = dep % K; pair tmp(dist(x, vec[m]), vec[m]); if (pq.size() < k) { pq.push(tmp); } else if (pq.top().first > tmp.first) { pq.pop(); pq.push(tmp); } if (x.x[cur] < vec[m].x[cur]) { query(x, k, lson); if (pq.top().first > sqr(x.x[cur] - vec[m].x[cur])) { query(x, k, rson); } } else { query(x, k, rson); if (pq.top().first > sqr(x.x[cur] - vec[m].x[cur])) { query(x, k, lson); } } } int main() { int n, t, m; while (~scanf("%d%d", &n, &K)) { for (int i = 1; i <= n; ++i) { for (int j = 0; j < K; ++j) { scanf("%d", &origin[i].x[j]); } vec[i] = origin[i]; } build(1, n); scanf("%d", &t); while (t--) { for (int i = 0; i < K; ++i) { scanf("%d", &pt.x[i]); } scanf("%d", &m); query(pt, m, 1, n); for (int i = 0; i < m; ++i) { ans[i] = pq.top().second; pq.pop(); } printf("the closest %d points are:\n", m); for (int i = m - 1; i >= 0; --i) { ans[i].output(); } } } } //支持点的插入和删除 #define lson kdt[rt].ls,dep+1 #define rson kdt[rt].rs,dep+1 struct kdnode { int ls, rs, x[DIM]; bool flag; //删点标记 } kdt[N]; inline ll sqr(int x) { return (ll)x * x; } ll dist(const kdnode &a, const kdnode &b) { ll ret = 0; for (int i = 0; i < DIM; ++i) { ret += sqr(a.x[i] - b.x[i]); } return ret; } int root, tot; void init() { tot = 0; root = -1; } int add(int pt[]) { kdt[tot].flag = false; kdt[tot].ls = kdt[tot].rs = -1; for (int i = 0; i < DIM; ++i) { kdt[tot].x[i] = pt[i]; } return tot++; } void insert(int pt[], int rt, int dep = 0) { dep %= DIM; if (pt[dep] < kdt[rt].x[dep]) { if (!~kdt[rt].ls) { kdt[rt].ls = add(pt); } else { insert(pt, lson); } } else { if (!~kdt[rt].rs) { kdt[rt].rs = add(pt); } else { insert(pt, rson); } } } //求最近点距离 ll query(const kdnode &pt, int rt, int dep = 0) { if (!~rt) { return INF; } dep %= DIM; ll ret = INF, tmp = sqr(kdt[rt].x[dep] - pt.x[dep]); if (!kdt[rt].flag) { ret = dist(kdt[rt], pt); } if (pt.x[dep] <= kdt[rt].x[dep]) { ret = min(ret, query(pt, lson)); if (tmp < ret) { ret = min(ret, query(pt, rson)); } } if (pt.x[dep] >= kdt[rt].x[dep]) { ret = min(ret, query(pt, rson)); if (tmp < ret) { ret = min(ret, query(pt, lson)); } } return ret; } //查询区间内有多少个点 int query(int pt1[], int pt2[], int rt, int dep = 0) { if (!~rt) { return 0; } dep %= DIM; int ret = 0, cur; for (cur = 0; cur < DIM; ++cur) { if (kdt[rt].x[cur] < pt1[cur] || kdt[rt].x[cur] > pt2[cur]) { break; } } if (cur == DIM) { ++ret; } if (pt2[dep] < kdt[rt].x[dep]) { ret += query(pt1, pt2, lson); } else if (pt1[dep] >= kdt[rt].x[dep]) { ret += query(pt1, pt2, rson); } else { ret += query(pt1, pt2, lson); ret += query(pt1, pt2, rson); } return ret; } //划分树 int part[20][N]; //表示每层每个位置的值 int sorted[N]; //已经排序好的数 int tol[20][N]; //tol[p][i] 表示第i层从1到i有数分入左边 void build(int l, int r, int dep) { if (l == r) { return; } int m = l + r >> 1, cnt = m - l + 1; //表示等于中间值而且被分入左边的个数 for (int i = l; i <= r; ++i) { if (part[dep][i] < sorted[m]) { --cnt; } } int lpos = l, rpos = m + 1; for (int i = l; i <= r; ++i) { if (part[dep][i] < sorted[m]) { part[dep + 1][lpos++] = part[dep][i]; } else if (part[dep][i] == sorted[m] && cnt > 0) { part[dep + 1][lpos++] = part[dep][i]; --cnt; } else { part[dep + 1][rpos++] = part[dep][i]; } tol[dep][i] = tol[dep][l - 1] + lpos - l; } build(l, m, dep + 1); build(m + 1, r, dep + 1); } //离线查询区间第k大的数, [L, R]是要查询的小区间, [l, r]是大区间 int query(int L, int R, int k, int l, int r, int dep) { if (L == R) { return part[dep][L]; } int m = l + r >> 1, cnt = tol[dep][R] - tol[dep][L - 1]; if (cnt >= k) { int tl = l + tol[dep][L - 1] - tol[dep][l - 1], tr = tl + cnt - 1; return query(tl, tr, k, l, m, dep + 1); } else { int tr = R + tol[dep][r] - tol[dep][R], tl = tr - (R - L - cnt); return query(tl, tr, k - cnt, m + 1, r, dep + 1); } } //左偏树 //可并堆的一种实现, 可以在O(logn)的时间内实现堆的push、pop和两个堆的合并操作, 以及O(1)时间的取堆顶操作 int val[N], ls[N], rs[N], dep[N], fa[N]; void init(int n) { for (int i = 1; i <= n; ++i) { scanf("%d", &val[i]); ls[i] = rs[i] = dep[i] = 0; fa[i] = i; } } int find(int x) { return x == fa[x] ? x : fa[x] = findfa(fa[x]); } int merge(int x, int y) { if (!x || !y) { return x | y; } if (val[x] < val[y]) { swap(x, y); } rs[x] = merge(rs[x], y); fa[rs[x]] = x; if (dep[ls[x]] < dep[rs[x]]) { swap(ls[x], rs[x]); } dep[x] = dep[rs[x]] + 1; return x; } int push(int x, int y) { return merge(x, y); } int pop(int x) { int a = ls[x], b = rs[x]; ls[x] = rs[x] = dep[x] = 0; fa[x] = x; fa[a] = a; fa[b] = b; return merge(a, b); } //POJ 2201 int main() { int n, m, x, y; while (~scanf("%d", &n)) { init(n); scanf("%d", &m); while (m--) { scanf("%d%d", &x, &y); int a = find(x), b = find(y); if (a == b) { puts("-1"); } else { val[a] >>= 1; val[b] >>= 1; a = push(pop(a), a); b = push(pop(b), b); printf("%d\n", val[merge(a, b)]); } } } } //笛卡尔树 //考虑一个键值对的序列, 当键与键, 值与值之间互不相同时, 它们可以唯一地构成这样一棵二叉树: //key在中序遍历时呈升序, 满足二叉查找树性质; 父节点的value大于子节点的value, 满足堆的性质. //一个键值对序列的笛卡儿树可以O(n)时间内构造出来 //POJ2201 const int N = 50005; int idx[N], n; struct Cartesian_Tree { int root, key[N], val[N], ch[N][2], pre[N]; void init() { for (int i = 1; i <= n; ++i) { scanf("%d%d", &key[i], &val[i]); ch[i][0] = ch[i][1] = pre[i] = 0; } } void build() { static int st[N]; int top = -1; for (int i = 1; i <= n; ++i) { int k = top; while (k >= 0 && val[st[k]] > val[idx[i]]) { --k; } if (~k) { pre[idx[i]] = st[k]; ch[st[k]][1] = idx[i]; } if (k < top) { pre[st[k + 1]] = idx[i]; ch[idx[i]][0] = st[k + 1]; } st[++k] = idx[i]; top = k; } root = st[0]; } } ct; bool cmp(int x, int y) { return ct.key[x] < ct.key[y]; } int main() { while (~scanf("%d", &n)) { ct.init(); for (int i = 1; i <= n; ++i) { idx[i] = i; } sort(idx + 1, idx + n + 1, cmp); ct.build(); puts("YES"); for (int i = 1; i <= n; ++i) { printf("%d %d %d\n", ct.pre[i], ct.ch[i][0], ct.ch[i][1]); } } }