题解详见洛谷题解区。这里直接放代码了。
关于实现的几点心得:
(1)用虚拟节点nil代替空指针NULL/nullptr,对nil的任何操作都不会影响实际节点,从而避免了大量的判断空指针的过程。
(2)善用throw和<stdexcept>查错。
(3)下放标记时只需保证从根节点到目标节点依次处理一遍,因此在findKth的过程中不断下放标记,之后splay和旋转过程就不必再检查标记了。、
(4)打标记要用异或运算(两个标记会相消),不要直接赋值成true。
(5)初始时将Splay树构造成线形并不会影响均摊复杂度,所以无需用分治法建树。
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <stdexcept> 5 6 int N, K; 7 8 struct Node; 9 extern Node *nil; 10 11 struct NilFlag {}; 12 struct Node 13 { 14 Node *ch[2], *par; 15 int val, size; 16 bool flag; 17 18 Node(Node* p, int v): par(p), val(v), size(1), flag(false) { 19 ch[0] = ch[1] = nil; 20 } 21 Node(NilFlag): par(this), val(0), size(0), flag(false) { 22 ch[0] = ch[1] = this; 23 } 24 }; 25 26 Node *nil = new Node(NilFlag()); 27 28 inline int getDir(Node* p) { 29 return p == p->par->ch[0] ? 0 : 1; 30 } 31 32 void pushDown(Node* p) 33 { 34 if (!p->flag) 35 return; 36 37 std::swap(p->ch[0], p->ch[1]); 38 p->ch[0]->flag ^= 1; 39 p->ch[1]->flag ^= 1; 40 41 p->flag = false; 42 } 43 44 void pushUp(Node* p) { 45 p->size = p->ch[0]->size + p->ch[1]->size + 1; 46 } 47 48 void rotate(Node* p) 49 { 50 Node *temp = p->par; 51 int dir = getDir(p); 52 53 temp->ch[dir] = p->ch[dir ^ 1]; 54 p->ch[dir ^ 1]->par = temp; 55 56 p->par = temp->par; 57 temp->par->ch[getDir(temp)] = p; 58 59 temp->par = p; 60 p->ch[dir ^ 1] = temp; 61 62 pushUp(temp); 63 pushUp(p); 64 } 65 66 inline void zig(Node* p) { rotate(p); } 67 inline void zigzig(Node* p) { rotate(p->par); rotate(p); } 68 inline void zigzag(Node* p) { rotate(p); rotate(p); } 69 70 struct Splay 71 { 72 Node *root; 73 74 Splay(): root(nil) {} 75 void splay(Node* p, Node* top = nil) 76 { 77 while (p->par != top) 78 { 79 if (p->par->par == top) 80 { 81 zig(p); 82 break; 83 } 84 if (getDir(p) == getDir(p->par)) 85 zigzig(p); 86 else 87 zigzag(p); 88 } 89 if (top == nil) 90 root = p; 91 } 92 93 void init() 94 { 95 root = new Node(nil, 0); 96 root->size = N + 2; 97 Node *last = root; 98 99 for (int i = 1; i <= N + 1; i++) 100 { 101 Node *cur; 102 cur = last->ch[1] = new Node(last, i); 103 cur->size = N + 2 - i; 104 last = cur; 105 } 106 } 107 108 Node* findKth(int k) 109 { 110 Node *cur = root; 111 while (cur != nil) 112 { 113 pushDown(cur); 114 115 if (cur->ch[0]->size == k - 1) 116 return cur; 117 if (cur->ch[0]->size < k - 1) 118 { 119 k -= (cur->ch[0]->size + 1); 120 cur = cur->ch[1]; 121 } 122 else 123 cur = cur->ch[0]; 124 } 125 throw std::logic_error("K-th value not found!"); 126 } 127 128 void flipRange(int l, int r) 129 { 130 Node *p = findKth(l); 131 splay(p, nil); 132 133 Node *q = findKth(r + 2); 134 splay(q, p); 135 136 q->ch[0]->flag ^= 1; 137 } 138 139 void dfs(Node* p) 140 { 141 pushDown(p); 142 143 if (p->ch[0] != nil) 144 dfs(p->ch[0]); 145 146 if (p->val >= 1 && p->val <= N) 147 printf("%d ", p->val); 148 149 if (p->ch[1] != nil) 150 dfs(p->ch[1]); 151 } 152 void printAns() { dfs(root); } 153 }; 154 155 int main() 156 { 157 scanf("%d%d", &N, &K); 158 Splay splay; 159 splay.init(); 160 161 for (int l, r, i = 0; i < K; i++) 162 { 163 scanf("%d%d", &l, &r); 164 splay.flipRange(l, r); 165 } 166 splay.printAns(); 167 168 return 0; 169 }