OJ-Problems-Source/.ACM-Templates/TXTs/数据结构.txt
2016-11-22 09:38:35 +08:00

2210 lines
58 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//一维树状数组
//单点修改 + 单点查询 + 区间修改 + 区间查询 + 区间最值
int n;
template<typename T> 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<int> bit;
//二维树状数组
//单点修改 + 单点查询 + 区域修改 + 区域查询
int n, m;
template<typename T> 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<int> bit;
//线段树 单点修改 + 区间查询
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
template<typename T> 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<int> st;
//线段树 区间查询/修改 + 延迟标记
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
template<typename T> 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<int> 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<typename T> 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<int> 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<typename T> 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<int> 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<typename T> 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<int> 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.53倍, 线段树的25倍.
//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<pair<int, point>> 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<int, point> 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]);
}
}
}