刚开始学spaly,所以一上来不会打标记,后来想了想splay的区间操作和线段树其实基本一样。
lazy标记的下推注意一下, update时如果直接进行splay操作的话会因lazy标记没有下推而出错,正确做法是在splay操作前先进行一个区间第k大查询操作(因为区间反转破坏了二叉搜索树的性质,所以我们只能进行区间第k大的查询来辅助下推)
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 1e5 + 10; int n, m; struct Splay { int sz, root, fa[maxn], ch[maxn][2], key[maxn], size[maxn], lazy[maxn]; void newnode(int x, int f, int v) { fa[x] = f, key[x] = v; size[x] = 1; } void pushup(int x) { if (!x) return; size[x] = size[ch[x][0]] + size[ch[x][1]] + 1; } void pushdown(int x) { if (!x || !lazy[x]) return; lazy[ch[x][0]] ^= 1; lazy[ch[x][1]] ^= 1; swap(ch[ch[x][0]][0], ch[ch[x][0]][1]); swap(ch[ch[x][1]][0], ch[ch[x][1]][1]); lazy[x] = 0; } int build(int l, int r, int f) { if (l > r) return 0; int mid = (l + r) >> 1; int x = ++sz; newnode(x, f, mid); ch[x][0] = build(l, mid-1, x); ch[x][1] = build(mid+1, r, x); pushup(x); return x; } int pos(int x) { return ch[fa[x]][1] == x; } void rotate(int x) { int y = fa[x], z = fa[y], posx = pos(x), posy = pos(y); ch[y][posx] = ch[x][posx^1]; fa[ch[y][posx]] = y; ch[x][posx^1] = y; fa[y] = x; fa[x] = z; if (z) ch[z][posy] = x; pushup(y); pushup(x); } void splay(int x, int y) { for (int f; (f=fa[x]) != y; rotate(x)) { if (fa[f] != y) rotate(pos(x) == pos(f)?f:x); } if (y == 0) root = x; } int kth(int x, int k) { pushdown(x); if (size[ch[x][0]]+1 == k) return x; if (size[ch[x][0]]+1 > k) return kth(ch[x][0], k); else return kth(ch[x][1], k-size[ch[x][0]]-1); } void update(int l, int r) { int x = kth(root, l), y = kth(root, r); splay(x, 0); splay(y, x); int z = ch[y][0]; swap(ch[z][0], ch[z][1]); lazy[z] ^= 1; } void query(int x) { if (!x) return; pushdown(x); query(ch[x][0]); if (1 <= key[x]-1 && key[x]-1 <= n) printf("%d ", key[x]-1); query(ch[x][1]); } }ac; int main() { int l, r; scanf("%d%d", &n, &m); ac.root = ac.build(1, n+2, 0); while (m--) { scanf("%d%d", &l, &r); l++, r++; ac.update(l-1, r+1); } ac.query(ac.root); printf("\n"); return 0; }