NOIP 2017 列队 - Splay - 树状数组

题目传送门

  传送点I

  传送点II

题目大意

  (家喻户晓的题目应该不需要大意)

  (我之前咋把NOIP 2017打成了NOIP 2018,好绝望)

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 }
Splay

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 }
posted @ 2018-10-15 13:31 阿波罗2003 阅读(...) 评论(...) 编辑 收藏