OJ-Problems-Source/.ACM-Templates/.Not classified/数据结构.cpp

2210 lines
61 KiB
C++
Raw Normal View History

2016-08-13 23:07:20 +08:00
//一维树状数组
//单点修改 + 单点查询 + 区间修改 + 区间查询 + 区间最值
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]);
}
}
}