voidrotate(int x){ int y = tr[x].p, z = tr[y].p; // k=0: x 是左儿子 // k=1: x 是右儿子 int k = tr[y].s[1] == x; // 更新 z-y 为 z-x tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z; // 更新 x-B 为 y-B tr[y].s[k] = tr[x].s[k ^ 1], tr[tr[x].s[k ^ 1]].p = y; // 更新 y-x 为 x-y tr[x].s[k ^ 1] = y, tr[y].p = x; // 先 pushup 下面的 y, 再 pushup 上面的 x pushup(y), pushup(x); }
voidsplay(int x, int k){ while (tr[x].p != k) { int y = tr[x].p, z = tr[y].p; if (z != k) if ((tr[y].s[0] == x) ^ (tr[z].s[0] == y)) rotate(x); elserotate(y); rotate(x); } if (k == 0) root = x; }
voidoutput(int u){ pushdown(u); if (tr[u].s[0]) output(tr[u].s[0]); if (tr[u].v > 0 && tr[u].v <= n) printf("%d ", tr[u].v); if (tr[u].s[1]) output(tr[u].s[1]); }
// 中序遍历的第 k 个数 intget_k(int k){ int u = root; while (u) { pushdown(u); if (tr[tr[u].s[0]].size >= k) u = tr[u].s[0]; elseif (tr[tr[u].s[0]].size + 1 == k) return u; else { k -= tr[tr[u].s[0]].size + 1; u = tr[u].s[1]; } } return-1; }
voidinsert(int v){ int u = root, p = 0; while (u) p = u, u = tr[u].s[v > tr[u].v]; u = ++idx; tr[u].init(v, p); if (p) tr[p].s[v > tr[p].v] = u; // 插入之后把它转到根节点上 splay(u, 0); }
intmain(){ scanf("%d%d", &n, &m); for (int i = 0; i <= n+1; i++) insert(i); while (m--) { int l, r; scanf("%d%d", &l, &r); l = get_k(l), r = get_k(r+2); splay(l, 0), splay(r, l); // 找到满足 l < v < r 的子树 tr[tr[r].s[0]].flag ^= 1; } output(root); return0; }
voidrotate(int x){ int y = tr[x].p, z = tr[y].p; int k = tr[y].s[1] == x; tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z; tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y; tr[x].s[k^1] = y, tr[y].p = x; pushup(y), pushup(x); }
voidsplay(int x, int k){ while (tr[x].p != k) { int y = tr[x].p, z = tr[y].p; if (z != k) { if ((tr[y].s[0] == x) ^ (tr[z].s[0] == y)) rotate(x); elserotate(y); } rotate(x); }
if (k == 0) root = x; }
intget_rank(int v){ int u = root, rk = 0; while (u) { if (v < tr[u].v) u = tr[u].s[0]; else { // 左子树全部比 v 小 rk += tr[tr[u].s[0]].size; if (v == tr[u].v) { splay(u, 0); return rk + 1; } // 当前结点也比 v 小 rk += tr[u].cnt; u = tr[u].s[1]; } } exit(-1); }
// 这个函数比较容易写错 intget_kth(int k){ int u = root; while (u) { // 左子树中包含了第 k 大数 if (tr[tr[u].s[0]].size >= k) u = tr[u].s[0]; // 当前结点包含了第 k 大数 elseif (tr[tr[u].s[0]].size + tr[u].cnt >= k) return tr[u].v; else { // 把右儿子当成根继续找 k -= tr[tr[u].s[0]].size + tr[u].cnt; u = tr[u].s[1]; } } exit(-1); }
voidinsert(int v){ int u = root, p = 0; while (u && tr[u].v != v) p = u, u = tr[u].s[v > tr[u].v]; if (u) tr[u].cnt++; else { u = ++idx; tr[u].init(p, v); if (p) tr[p].s[v > tr[p].v] = u; } splay(u, 0); }
voiddel(int v){ // 转到根 get_rank(v); if (tr[root].cnt > 1) tr[root].cnt--; else { // 由于存在两个哨兵 因此前驱和后继是一定存在的 int l = tr[root].s[0], r = tr[root].s[1]; while (tr[l].s[1]) l = tr[l].s[1]; while (tr[r].s[0]) r = tr[r].s[0]; // 传统操作 splay(l, 0), splay(r, l); tr[r].s[0] = 0; pushup(r), pushup(l); } }
structNode { int s[2], p, v; int cnt; voidinit(int _p, int _v){ p = _p, v = _v; s[0] = s[1] = 0; cnt = 1; } } tr[N];
int root, idx;
voidrotate(int x){ int y = tr[x].p, z = tr[y].p; int k = tr[y].s[1] == x; tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z; tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y; tr[x].s[k^1] = y, tr[y].p = x; }
voidsplay(int x, int k){ while (tr[x].p != k) { int y = tr[x].p, z = tr[y].p; if (z != k) { if ((tr[y].s[0] == x) ^ (tr[z].s[0] == y)) rotate(x); elserotate(y); } rotate(x); } if (k == 0) root = x; }
voidinsert(int v){ int u = root, p = 0; while (u && tr[u].v != v) p = u, u = tr[u].s[v > tr[u].v]; if (u) tr[u].cnt++; else { u = ++idx; tr[u].init(p, v); if (p) tr[p].s[v > tr[p].v] = u; } splay(u, 0); }
intpre(){ int l = tr[root].s[0]; if (!l) return1e9; while (tr[l].s[1]) l = tr[l].s[1]; return tr[l].v; }
intsuf(){ int r = tr[root].s[1]; if (!r) return1e9; while (tr[r].s[0]) r = tr[r].s[0]; return tr[r].v; }
intmain(){ int n; scanf("%d", &n); int res; scanf("%d", &res); insert(res); n--; while (n--) { int v; scanf("%d", &v); insert(v); if (tr[root].cnt > 1) continue; int now = min(abs(pre() - v), abs(suf() - v)); res += now; } printf("%d\n", res); return0; }
[NOI2004] 郁闷的出纳员
题干过长,这里不粘过来了。
输入格式
第一行有两个非负整数 n 和 min,n 表示下面有多少条命令,min 表示工资下界。
接下来的 n 行,每行表示一条命令,命令可以是以下四种之一:
I 命令,格式为 I_k,表示新建一个工资档案,初始工资为 k。如果某员工的初始工资低于工资下界,他将立刻离开公司。
A 命令,格式为 A_k,表示把每位员工的工资加上 k。
S 命令,格式为 S_k,表示把每位员工的工资扣除 k。
F 命令,格式为 F_k,表示查询第 k 多的工资。
_(下划线)表示一个空格,I 命令、A 命令、S 命令中的 k 是一个非负整数,F 命令中的 k 是一个正整数。
在初始时,可以认为公司里一个员工也没有。
输出格式
输出行数为 F 命令的条数加一。对于每条 F 命令,你的程序要输出一行,仅包含一个整数,为当前工资第 k 多的员工所拿的工资数,如果 k 大于目前员工的数目,则输出 −1。
constint N = 1e5+10, INF = 1e9; structNode { int s[2], p, v, size; voidinit(int _p, int _v){ p = _p, v = _v; size = 1; } } tr[N]; int n, m, root, delta, idx;
voidrotate(int x){ int y = tr[x].p, z = tr[y].p; int k = tr[y].s[1] == x; tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z; tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y; tr[x].s[k^1] = y, tr[y].p = x; pushup(y), pushup(x); }
voidsplay(int x, int k){ while (tr[x].p != k) { int y = tr[x].p, z = tr[y].p; if (z != k) { if ((tr[y].s[0] == x) ^ (tr[z].s[0] == y)) rotate(x); elserotate(y); } rotate(x); } // splay 需要修改 root if (k == 0) root = x; }
intinsert(int v){ int u = root, p = 0; while (u) p = u, u = tr[u].s[v > tr[u].v]; u = ++idx; tr[u].init(p, v); if (p) tr[p].s[v > tr[p].v] = u; splay(u, 0); return u; }
// 大于等于 v 的第一个结点 intget(int v){ int u = root, res = -1; while (u) { if (tr[u].v >= v) res = u, u = tr[u].s[0]; else u = tr[u].s[1]; } return res; }
intget_kth(int k){ int u = root; while (u) { if (tr[tr[u].s[0]].size >= k) u = tr[u].s[0]; elseif (tr[tr[u].s[0]].size + 1 == k) return tr[u].v + delta; else { k -= tr[tr[u].s[0]].size + 1; u = tr[u].s[1]; } } return-1; }
intmain(){ scanf("%d%d", &n, &m); int L = insert(-INF), total = 0; insert(INF); while (n--) { char op[2]; int k; scanf("%s%d", op, &k); if (*op == 'I') { if (k < m) continue; k -= delta; insert(k); total++; } elseif (*op == 'A') delta += k; elseif (*op == 'S') { delta -= k; int R = get(m-delta); splay(R, 0), splay(L, R); tr[L].s[1] = 0; pushup(L), pushup(R); } else { if (tr[root].size - 2 < k) puts("-1"); elseprintf("%d\n", get_kth(tr[root].size - k)); } }
printf("%d\n", total - (tr[root].size - 2)); return0; }
[HNOI2012] 永无乡
永无乡包含 n 座岛,编号从 1 到 n ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 n 座岛排名,名次用 1 到 n 来表示。
某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。
如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连通的。
现在有两种操作:
B x y 表示在岛 x 与岛 y 之间修建一座新桥。
Q x k 表示询问当前与岛 x 连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪座,请你输出那个岛的编号,如果不存在输出 -1。
structNode { int s[2], v, id, p; int size; voidinit(int _v, int _id, int _p){ v = _v, id = _id, p = _p; size = 1; } } tr[M]; int root[N], p[N], n, m, idx;
voidrotate(int x){ int y = tr[x].p, z = tr[y].p; int k = tr[y].s[1] == x; tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z; tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y; tr[x].s[k^1] = y, tr[y].p = x; pushup(y), pushup(x); }
voidsplay(int x, int k, int rid){ while (tr[x].p != k) { int y = tr[x].p, z = tr[y].p; if (z != k) { if ((tr[y].s[0] == x) ^ (tr[z].s[0] == y)) rotate(x); elserotate(y); } rotate(x); } if (k == 0) root[rid] = x; }
voidinsert(int v, int id, int rid){ int u = root[rid], p = 0; while (u) p = u, u = tr[u].s[v > tr[u].v]; u = ++idx; tr[u].init(v, id, p); if (p) tr[p].s[v > tr[p].v] = u; splay(u, 0, rid); }
voiddfs(int u, int rid){ if (tr[u].s[0]) dfs(tr[u].s[0], rid); if (tr[u].s[1]) dfs(tr[u].s[1], rid); insert(tr[u].v, tr[u].id, rid); }
intget_kth(int rid, int k){ int u = root[rid]; while (u) { if (tr[tr[u].s[0]].size >= k) u = tr[u].s[0]; elseif (tr[tr[u].s[0]].size + 1 == k) return tr[u].id; else { k -= tr[tr[u].s[0]].size + 1; u = tr[u].s[1]; } } return-1; }
intmain(){ scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { p[i] = root[i] = i; int v; scanf("%d", &v); tr[root[i]].init(v, i, 0); } idx = n; while (m--) { int a, b; scanf("%d%d", &a, &b); a = find(a), b = find(b); if (a != b) { // root[a], root[b] 会在 splay 的时候变化 if (tr[root[a]].size > tr[root[b]].size) swap(a, b); dfs(root[a], b); p[a] = b; } } scanf("%d", &m); while (m--) { char op[2]; int x, y; scanf("%s%d%d", op, &x, &y); if (*op == 'B') { x = find(x), y = find(y); if (x != y) { if (tr[root[x]].size > tr[root[y]].size) swap(x, y); dfs(root[x], y); p[x] = y; } } else { x = find(x); if (tr[root[x]].size < y) puts("-1"); elseprintf("%d\n", get_kth(x, y)); } } return0; }
voidrotate(int x){ int y = tr[x].p, z = tr[y].p; int k = tr[y].s[1] == x; tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z; tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y; tr[x].s[k^1] = y, tr[y].p = x; pushup(y), pushup(x); }
voidsplay(int u, int k){ while (tr[u].p != k) { int y = tr[u].p, z = tr[y].p; if (z != k) { if ((tr[y].s[0] == u) ^ (tr[z].s[0] == y)) rotate(u); elserotate(y); } rotate(u); } if (k == 0) root = u; }
intget_kth(int k){ int u = root; while (u) { pushdown(u); if (tr[tr[u].s[0]].size >= k) u = tr[u].s[0]; elseif (tr[tr[u].s[0]].size + 1 == k) return u; else { k -= tr[tr[u].s[0]].size + 1; u = tr[u].s[1]; } } return-1; }
intbuild(int v[], int l, int r, int p){ int mid = (l + r) >> 1; int u = ++idx; tr[u].init(v[mid], p); if (l < mid) tr[u].s[0] = build(v, l, mid-1, u); if (mid < r) tr[u].s[1] = build(v, mid+1, r, u); pushup(u); return u; }
int buf[N]; char op[20];
intmain(){ scanf("%d%d", &n, &m); buf[0] = buf[n+1] = -INF; tr[0].v = tr[0].tmax = -INF; for (int i = 1; i <= n; i++) scanf("%d", &buf[i]); root = build(buf, 0, n+1, 0); int pos = -1, tot = -1, c = -1; while (m--) { scanf("%s", op); if (!strcmp(op, "INSERT")) { scanf("%d%d", &pos, &tot); for (int i = 1; i <= tot; i++) scanf("%d", &buf[i]); int L = get_kth(pos+1), R = get_kth(pos+2); splay(L, 0), splay(R, L); tr[R].s[0] = build(buf, 1, tot, R); pushup(R), pushup(L); } elseif (!strcmp(op, "DELETE")) { scanf("%d%d", &pos, &tot); int L = get_kth(pos), R = get_kth(pos+tot+1); splay(L, 0), splay(R, L); tr[R].s[0] = 0; pushup(R), pushup(L); } elseif (!strcmp(op, "MAKE-SAME")) { scanf("%d%d%d", &pos, &tot, &c); int L = get_kth(pos), R = get_kth(pos+tot+1); splay(L, 0), splay(R, L); tr[tr[R].s[0]].makesame(c); pushup(R), pushup(L); } elseif (!strcmp(op, "REVERSE")) { scanf("%d%d", &pos, &tot); int L = get_kth(pos), R = get_kth(pos+tot+1); splay(L, 0), splay(R, L); tr[tr[R].s[0]].reverse(); pushup(R), pushup(L); } elseif (!strcmp(op, "GET-SUM")) { scanf("%d%d", &pos, &tot); int L = get_kth(pos), R = get_kth(pos+tot+1); splay(L, 0), splay(R, L); printf("%d\n", tr[tr[R].s[0]].sum); } elseprintf("%d\n", tr[root].tmax); } return0; }
voidrotate(int x){ int y = tr[x].p, z = tr[y].p; int k = tr[y].s[1] == x; tr[z].s[tr[z].s[1] == y] = x, tr[x].p = z; tr[y].s[k] = tr[x].s[k^1], tr[tr[x].s[k^1]].p = y; tr[x].s[k^1] = y, tr[y].p = x; pushup(y), pushup(x); }
voidsplay(int u, int k){ while (tr[u].p != k) { int y = tr[u].p, z = tr[y].p; if (z != k) { if ((tr[y].s[0] == u) ^ (tr[z].s[0] == y)) rotate(u); elserotate(y); } rotate(u); } if (k == 0) root = u; }
intget_kth(int k){ int u = root; while (u) { pushdown(u); if (tr[tr[u].s[0]].size >= k) u = tr[u].s[0]; elseif (tr[tr[u].s[0]].size + 1 == k) return u; else { k -= tr[tr[u].s[0]].size + 1; u = tr[u].s[1]; } } return-1; }
vector<int> ava;
intbuild(int v[], int l, int r, int p){ int mid = (l + r) >> 1; int u = ava.back(); ava.pop_back(); tr[u].init(v[mid], p); if (l < mid) tr[u].s[0] = build(v, l, mid-1, u); if (mid < r) tr[u].s[1] = build(v, mid+1, r, u); pushup(u); return u; }
voiddfs(int u){ if (tr[u].s[0]) dfs(tr[u].s[0]); if (tr[u].s[1]) dfs(tr[u].s[1]); ava.push_back(u); }
int buf[(int)4e6+10]; char op[20];
intmain(){ scanf("%d%d", &n, &m); buf[0] = buf[n+1] = -INF; tr[0].v = tr[0].tmax = -INF; for (int i = 1; i < N; i++) ava.push_back(i); for (int i = 1; i <= n; i++) scanf("%d", &buf[i]); root = build(buf, 0, n+1, 0); int pos = -1, tot = -1, c = -1; while (m--) { scanf("%s", op); if (!strcmp(op, "INSERT")) { scanf("%d%d", &pos, &tot); for (int i = 0; i < tot; i++) scanf("%d", &buf[i]); int L = get_kth(pos+1), R = get_kth(pos+2); splay(L, 0), splay(R, L); tr[R].s[0] = build(buf, 0, tot-1, R); pushup(R), pushup(L); } elseif (!strcmp(op, "DELETE")) { scanf("%d%d", &pos, &tot); int L = get_kth(pos), R = get_kth(pos+tot+1); splay(L, 0), splay(R, L); dfs(tr[R].s[0]); tr[R].s[0] = 0; pushup(R), pushup(L); } elseif (!strcmp(op, "MAKE-SAME")) { scanf("%d%d%d", &pos, &tot, &c); int L = get_kth(pos), R = get_kth(pos+tot+1); splay(L, 0), splay(R, L); tr[tr[R].s[0]].makesame(c); pushup(R), pushup(L); } elseif (!strcmp(op, "REVERSE")) { scanf("%d%d", &pos, &tot); int L = get_kth(pos), R = get_kth(pos+tot+1); splay(L, 0), splay(R, L); tr[tr[R].s[0]].reverse(); pushup(R), pushup(L); } elseif (!strcmp(op, "GET-SUM")) { scanf("%d%d", &pos, &tot); int L = get_kth(pos), R = get_kth(pos+tot+1); splay(L, 0), splay(R, L); printf("%d\n", tr[tr[R].s[0]].sum); } elseprintf("%d\n", tr[root].tmax); } return0; }