NOIP 2017 列队 - Splay - 树状数组
Solution 1 Splay
每行一颗Splay,没有动过的地方直接一段一个点。
最后一列单独一颗Splay。
暴力模拟即可。
Soluion 2 Splay II
我们考虑倒推。对于每个询问倒推出在第一次操作前时的位置。
考虑每个出队操作对答案的影响。
假设询问$(x, y)$,那么最后一列横坐标大于等于$x$的位置,横坐标都会加1.
第$x$行,纵坐标大于等于$y$的位置,纵坐标都会加1.
然后再把这个位置塞进$(x, y)$。
然后暴力模拟就好了。
Code
1 /** 2 * uoj 3 * Problem#334 4 * Accepted 5 * Time: 4027ms 6 * Memory: 25700k 7 */ 8 #include <iostream> 9 #include <cassert> 10 #include <cstdlib> 11 #include <cstdio> 12 #ifndef WIN32 13 #define Auto "%lld" 14 #else 15 #define Auto "%I64d" 16 #endif 17 using namespace std; 18 typedef bool boolean; 19 #define ll long long 20 21 const int N = 3e5 + 5; 22 23 typedef class SplayNode { 24 public: 25 int val, tg, id; 26 SplayNode *ch[2]; 27 SplayNode *fa; 28 29 SplayNode() { } 30 31 void pushDown() { 32 for (int i = 0; i < 2; i++) 33 if (ch[i]) 34 ch[i]->val += tg, ch[i]->tg += tg; 35 tg = 0; 36 } 37 38 int which(SplayNode* p) { 39 return p == ch[1]; 40 } 41 }SplayNode; 42 43 SplayNode pool[N << 1]; 44 SplayNode* top = pool; 45 46 SplayNode* newnode(int val, int id) { 47 top->val = val, top->id = id; 48 top->ch[0] = top->ch[1] = top->fa = NULL; 49 top->tg = 0; 50 return top++; 51 } 52 53 SplayNode* stps[N]; 54 55 typedef class Splay { 56 protected: 57 void rotate(SplayNode* p) { 58 SplayNode *fa = p->fa, *ffa = fa->fa; 59 int df = fa->which(p); 60 SplayNode* ls = p->ch[df ^ 1]; 61 62 p->fa = ffa; 63 p->ch[df ^ 1] = fa; 64 fa->fa = p; 65 fa->ch[df] = ls; 66 if (ls) 67 ls->fa = fa; 68 if (ffa) 69 ffa->ch[ffa->which(fa)] = p; 70 } 71 72 void splay(SplayNode* p, SplayNode* fa) { 73 SplayNode** st = stps; 74 for (SplayNode* q = p; q; *(++st) = q, q = q->fa); 75 for ( ; st != stps; (*st)->pushDown(), st--); 76 for ( ; p->fa != fa; rotate(p)) 77 if (p->fa->fa != fa) 78 rotate((p->fa->fa->which(p->fa) == p->fa->which(fa)) ? (p->fa) : (p)); 79 if (!fa) 80 rt = p; 81 } 82 public: 83 SplayNode* rt; 84 85 void insert(SplayNode*& p, SplayNode* fa, SplayNode* np) { 86 if (!p) { 87 p = np, np->fa = fa; 88 return; 89 } 90 if (p->tg) 91 p->pushDown(); 92 insert(p->ch[np->val > p->val], p, np); 93 } 94 95 boolean less_bound(int x) { // find the maximum number less than x and splay it 96 SplayNode* ret = NULL, *p = rt, *q = NULL; 97 while (p) { 98 q = p; 99 if (p->tg) 100 p->pushDown(); 101 if (p->val < x) 102 ret = p, p = p->ch[1]; 103 else 104 p = p->ch[0]; 105 } 106 if (ret) 107 splay(ret, NULL); 108 else if (q) 109 splay(q, NULL); 110 return ret != NULL; 111 } 112 113 void remove(SplayNode* p) { 114 splay(p, NULL); 115 if (!p->ch[1]) { 116 rt = p->ch[0]; 117 if (rt) 118 rt->fa = NULL; 119 return; 120 } 121 122 SplayNode* q = p->ch[1]; 123 while (q->ch[1]) 124 q = q->ch[1]; 125 splay(q, p); 126 q->ch[0] = p->ch[0]; 127 if (p->ch[0]) 128 p->ch[0]->fa = q; 129 rt = q; 130 } 131 132 SplayNode* findMax() { 133 SplayNode* p = rt; 134 while (p && p->ch[1]) { 135 if (p->tg) 136 p->pushDown(); 137 p = p->ch[1]; 138 } 139 if (p) 140 splay(p, NULL); 141 return p; 142 } 143 144 void insert(SplayNode* p) { 145 insert(rt, NULL, p); 146 splay(p, NULL); 147 } 148 149 void getLis(SplayNode**& vs, SplayNode* p) { 150 if (!p) 151 return; 152 if (p->tg) 153 p->pushDown(); 154 *(vs++) = p; 155 getLis(vs, p->ch[0]); 156 getLis(vs, p->ch[1]); 157 } 158 }Splay; 159 160 int n, m, q; 161 Splay ls[N]; // maintain for (1, 1) - (n, m - 1) 162 Splay rs; 163 int xs[N], ys[N]; 164 ll res[N]; 165 166 inline void init() { 167 scanf("%d%d%d", &n, &m, &q); 168 for (int i = 1; i <= q; i++) 169 scanf("%d%d", xs + i, ys + i); 170 } 171 172 int uf[N]; 173 174 int find(int x) { 175 return (uf[x] == x) ? (x) : (uf[x] = find(uf[x])); 176 } 177 178 inline void solve() { 179 for (int i = 1; i <= q; i++) 180 uf[i] = i; 181 182 SplayNode *p; 183 for (int i = q; i; i--) { 184 int x = xs[i], y = ys[i]; 185 while ((p = rs.findMax()) && p->val == n) 186 uf[find(p->id)] = i, rs.remove(p); 187 if (rs.rt) { 188 if (rs.less_bound(x)) { 189 p = rs.rt->ch[1]; 190 if (p) 191 p->val++, p->tg++; 192 } else 193 rs.rt->val++, rs.rt->tg++; 194 } 195 if (y == m) { 196 rs.insert(newnode(x, i)); 197 } else { 198 Splay& sp = ls[x]; 199 if (sp.rt) { 200 if (sp.less_bound(y)) { 201 p = sp.rt->ch[1]; 202 if (p) 203 p->val++, p->tg++; 204 } else 205 sp.rt->val++, sp.rt->tg++; 206 } 207 while ((p = sp.findMax()) && p->val == m) 208 rs.insert(newnode(x, p->id)), sp.remove(p); 209 sp.insert(newnode(y, i)); 210 } 211 } 212 213 SplayNode **pp, **pq; 214 for (int i = 1; i <= n; i++) { 215 pp = stps; 216 ls[i].getLis(pp, ls[i].rt); 217 for (pq = stps; pq != pp; pq++) 218 res[(*pq)->id] = (i - 1) * 1ll * m + (*pq)->val; 219 } 220 pp = stps; 221 rs.getLis(pp, rs.rt); 222 for (pq = stps; pq != pp; pq++) 223 res[(*pq)->id] = (*pq)->val * 1ll * m; 224 for (int i = 1; i <= q; i++) 225 printf(Auto"\n", res[find(i)]); 226 } 227 228 int main() { 229 init(); 230 solve(); 231 return 0; 232 }
Solution 3 BIT
考虑删掉的位置我们留下,如果我们知道所有按顺序被加进这一行的人,那么我们查找第$k$列的人相当于求第$k$大值。
我们可以利用树状数组预处理出每一行除去最后一列,每个询问是第几个加入这一行的数(原来的数依次看做第一个,第二个,...)。
然后开始处理询问。用类似的方法维护最后一列。
这样可以算每次询问,最后一列被拿走的数,以及当且行被加入的数。
Code
1 /** 2 * uoj 3 * Problem#334 4 * Accepted 5 * Time: 1673ms 6 * Memory: 32808b 7 */ 8 #include <iostream> 9 #include <cstdlib> 10 #include <cstdio> 11 #include <vector> 12 #ifndef WIN32 13 #define Auto "%lld" 14 #else 15 #define Auto "%I64d" 16 #endif 17 using namespace std; 18 typedef bool boolean; 19 20 template <typename T> 21 void pfill(T* pst, const T* ped, T val) { 22 for ( ; pst != ped; *(pst++) = val); 23 } 24 25 const int bzmax = 20; 26 const int N = 3e5 + 5; 27 28 typedef class IndexedTree { 29 public: 30 int *ar; 31 int s; 32 33 IndexedTree() { } 34 IndexedTree(int s):s(s) { 35 ar = new int[(s + 1)]; 36 pfill(ar, ar + s + 1, 0); 37 } 38 39 void add(int idx, int val) { 40 for ( ; idx <= s; idx += ((-idx) & idx)) 41 ar[idx] += val; 42 } 43 44 int kth(int k) { 45 int rt = 0, cur = 0; 46 for (int b = (1 << (bzmax - 1)); b; b >>= 1) 47 if ((rt | b) <= s && cur + ar[rt | b] < k) 48 rt += b, cur += ar[rt | b]; 49 return rt + 1; 50 } 51 }IndexedTree; 52 53 #define ll long long 54 #define pii pair<int, int> 55 #define fi first 56 #define sc second 57 58 int n, m, q, K; 59 int rk[N]; 60 IndexedTree it; 61 pii qs[N]; 62 vector<ll> lst; 63 vector<ll> vs[N]; 64 vector<pii> ms[N]; 65 66 inline void init() { 67 scanf("%d%d%d", &n, &m, &q); 68 K = max(n, m) + q; 69 it = IndexedTree(K); 70 for (int i = 1; i <= q; i++) { 71 scanf("%d%d", &qs[i].fi, &qs[i].sc); 72 if (qs[i].sc < m) 73 ms[qs[i].fi].push_back(pii(qs[i].sc, i)); 74 } 75 } 76 77 inline void solve() { 78 for (int i = 1; i <= K; i++) 79 it.add(i, 1); 80 for (int i = 1; i <= n; i++) { 81 for (vector<pii> :: iterator it = ms[i].begin(); it != ms[i].end(); it++) 82 ::it.add(rk[it->sc] = ::it.kth(it->fi), -1); 83 for (vector<pii> :: iterator it = ms[i].begin(); it != ms[i].end(); it++) 84 ::it.add(rk[it->sc], 1); 85 } 86 87 ll res; 88 for (int i = 1, x, y, p; i <= q; i++) { 89 x = qs[i].fi, y = qs[i].sc; 90 it.add(p = it.kth(x), -1); 91 res = ((p <= n) ? (p * 1ll * m) : (lst[p - n - 1])); 92 if (y < m) { 93 vs[x].push_back(res); 94 res = ((rk[i] <= m - 1) ? ((x - 1) * 1ll * m + rk[i]) : vs[x][rk[i] - m]); 95 } 96 lst.push_back(res); 97 printf(Auto"\n", res); 98 } 99 } 100 101 int main() { 102 init(); 103 solve(); 104 return 0; 105 }