我佛了,我这么大常数的写法竟然跑得还不算特别慢。。。
首先想到用一个splay按排名维护队列,那么操作都挺sb的,随便写写就行了吧。
然后就发现有问题, n ≤ 1 0 8 n\leq10^8 n≤108,这意味着好像不能把整棵树建出来(可以吗?我也不清楚==)。于是我们考虑一种结点分裂的做法,就是把一段区间合成一个结点,用到的时候再分裂。
那么既然这样我们还需要一个map来知道编号x对应的结点是哪一个。
然后问题出现了,要分裂结点的话意味着在map上要修改,而且不是改单点而是区间修改,于是我就把map改成了线段树
反正写得挺麻烦的不过仔细实现一下也还行。。。
另外为了不让树被卡成链,我在结点分裂的时候搞了一个可能没什么用的判断,就是可能分裂出一个左孩子也可能分裂出一个右孩子。脑补一下觉得有点用吧?…
#include <cctype>
#include <cstdio>
#include <climits>
#include <algorithm>
template <typename T> inline void read(T& x) {
int f = 0, c = getchar(); x = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) x = x * 10 + c - 48, c = getchar();
if (f) x = -x;
}
template <typename T, typename... Args>
inline void read(T& x, Args&... args) {
read(x); read(args...);
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + 48);
}
template <typename T> inline void writeln(T x) { write(x); puts(""); }
template <typename T> inline bool chkmin(T& x, const T& y) { return y < x ? (x = y, true) : false; }
template <typename T> inline bool chkmax(T& x, const T& y) { return x < y ? (x = y, true) : false; }
const int maxn = 1e5 + 7;
int n, m;
struct Sgt {
struct Node {
int val, lc, rc;
int tag;
Node() : val(0), lc(0), rc(0), tag(0) {}
};
Node T[maxn << 6];
int tot, root;
void update(int o) {
if (T[T[o].lc].val == T[T[o].rc].val) T[o].val = T[T[o].lc].val;
else T[o].val = 0;
}
void pushdown(int o) {
if (T[o].tag) {
if (!T[o].lc) T[o].lc = ++tot;
if (!T[o].rc) T[o].rc = ++tot;
T[T[o].lc].tag = T[T[o].rc].tag = T[o].tag;
T[T[o].lc].val = T[T[o].rc].val = T[o].tag;
T[o].tag = 0;
}
}
void modify(int &o, int lb, int rb, int l, int r, int na) {
if (l > rb || r < lb) return;
if (!o) o = ++tot;
if (l <= lb && r >= rb) {
T[o].tag = T[o].val = na;
return;
}
int mid = (lb + rb) >> 1;
pushdown(o);
modify(T[o].lc, lb, mid, l, r, na);
modify(T[o].rc, mid + 1, rb, l, r, na);
update(o);
}
int query(int o, int lb, int rb, int p) {
if (T[o].val) return T[o].val;
int mid = (lb + rb) >> 1;
pushdown(o);
if (p <= mid) return query(T[o].lc, lb, mid, p);
else return query(T[o].rc, mid + 1, rb, p);
}
void modify(int l, int r, int na) { modify(root, 1, 2e8, l, r, na); }
int query(int x) { return query(root, 1, 2e8, x); }
};
Sgt pos;
int fa[maxn << 6], ch[maxn << 6][2], lb[maxn << 6], rb[maxn << 6], size[maxn << 6], tot, root;
inline int iden(int x) { return ch[fa[x]][0] == x ? 0 : ch[fa[x]][1] == x ? 1 : -1; }
inline void update(int x) { size[x] = rb[x] - lb[x] + 1 + size[ch[x][0]] + size[ch[x][1]]; }
inline int split(int x) {
static int state = 1;
if (lb[x] < rb[x]) {
state ^= 1;
int mid = (lb[x] + rb[x]) >> 1;
int y = ++tot, z = ch[x][state];
if (z) fa[z] = y;
ch[y][state] = z;
fa[ch[x][state] = y] = x;
if (state) {
lb[y] = mid + 1; rb[y] = rb[x];
rb[x] = mid;
} else {
lb[y] = lb[x]; rb[y] = mid;
lb[x] = mid + 1;
}
pos.modify(lb[y], rb[y], y);
update(y);
return state;
} else return -1;
}
inline void rotate(int x) {
int d = iden(x), y = fa[x];
if (~iden(y)) ch[fa[y]][iden(y)] = x;
fa[x] = fa[y];
if ((ch[y][d] = ch[x][d ^ 1])) fa[ch[x][d ^ 1]] = y;
fa[ch[x][d ^ 1] = y] = x;
update(y); update(x);
}
inline void splay(int x, int &k) {
if (x == k) return;
int p = fa[k];
while (fa[x] != p) {
int y = fa[x];
if (fa[y] != p) rotate(iden(y) ^ iden(x) ? x : y);
rotate(x);
}
k = x;
}
inline int get_single(int x, int id) {
while (lb[x] < rb[x]) {
int d = split(x);
if (lb[x] > id || id > rb[x]) x = ch[x][d];
}
return x;
}
// d == 1 move_to_top; d == 0 move_to_bottom
inline int move(int x, int id, int d) {
x = get_single(x, id);
splay(x, root);
int ans = size[ch[x][0]] + 1;
int y = ch[x][d];
if (y) {
while (ch[y][d ^ 1]) y = ch[y][d ^ 1];
splay(y, ch[x][d]);
fa[ch[ch[x][d]][d ^ 1] = ch[x][d ^ 1]] = ch[x][d];
ch[x][d ^ 1] = 0;
update(ch[x][d]);
} else {
std::swap(ch[x][0], ch[x][1]);
}
return ans;
}
inline int findkth(int k) {
int x = root;
while (true) {
if (ch[x][0] && size[ch[x][0]] >= k) x = ch[x][0];
else {
if (ch[x][0]) k -= size[ch[x][0]];
if (k <= rb[x] - lb[x] + 1) {
splay(x, root);
return lb[x] + k - 1;
}
k -= rb[x] - lb[x] + 1;
x = ch[x][1];
}
}
}
inline int modify(int idx, int idy) {
int x = pos.query(idx);
x = get_single(x, idx);
splay(x, root);
int ans = size[ch[x][0]] + 1;
pos.modify(idx, idx, 0);
lb[x] = rb[x] = idy;
pos.modify(idy, idy, x);
return ans;
}
int main() {
read(n, m);
pos.modify(1, n, root = ++tot);
lb[root] = 1; rb[root] = size[root] = n;
int lastans = 0;
while (m--) {
int q; read(q);
if (q == 1) {
int x, y; read(x, y);
x -= lastans; y -= lastans;
writeln(lastans = modify(x, y));
} else if (q == 2) {
int x; read(x); x -= lastans;
writeln(lastans = move(pos.query(x), x, 1));
} else if (q == 3) {
int x; read(x); x -= lastans;
writeln(lastans = move(pos.query(x), x, 0));
} else {
int k; read(k); k -= lastans;
writeln(lastans = findkth(k));
}
}
return 0;
}