洛谷P2824 排序

解:splay + 线段树合并,分裂。

首先有个乱搞做法是外层拿splay维护,有序区间缩成splay上一个节点。内层再开个数据结构支持合并分裂有序集合。

内层我一开始想的是splay,然后就没有复杂度保证,乱搞。

后来发现可以用线段树分裂/合并来,全程复杂度一个log还能在线实时回答询问,NB!

解法二:二分答案 + 把原序列转成01序列来排序。这个我没写,但是感觉很神奇。

  1 #include <bits/stdc++.h>
  2 
  3 const int N = 100010, M = 20000010;
  4 
  5 namespace seg {
  6     int ls[M], rs[M], sum[M], tot, rt[N];
  7     void insert(int p, int l, int r, int &o) {
  8         if(!o) o = ++tot;
  9         if(l == r) {
 10             sum[o]++;
 11             return;
 12         }
 13         int mid = (l + r) >> 1;
 14         if(p <= mid) insert(p, l, mid, ls[o]);
 15         else insert(p, mid + 1, r, rs[o]);
 16         sum[o] = sum[ls[o]] + sum[rs[o]];
 17         return;
 18     }
 19     int merge(int x, int y) {
 20         if(!x || !y) return x | y;
 21         sum[x] += sum[y];
 22         ls[x] = merge(ls[x], ls[y]);
 23         rs[x] = merge(rs[x], rs[y]);
 24         return x;
 25     }
 26     int getKth(int k, int l, int r, int o) {
 27         if(l == r) return r;
 28         int mid = (l + r) >> 1;
 29         if(k <= sum[ls[o]]) return getKth(k, l, mid,  ls[o]);
 30         else return getKth(k - sum[ls[o]], mid + 1, r, rs[o]);
 31     }
 32     void split(int o, int &x, int &y, int k) {
 33         if(!o) {
 34             x = y = 0;
 35             return;
 36         }
 37         if(!k) {
 38             x = 0;
 39             y = o;
 40             return;
 41         }
 42         if(k == sum[o]) {
 43             x = o;
 44             y = 0;
 45             return;
 46         }
 47         if(k <= sum[ls[o]]) {
 48             x = ++tot;
 49             y = o;
 50             split(ls[o], ls[x], ls[y], k);
 51         }
 52         else {
 53             y = ++tot;
 54             x = o;
 55             split(rs[o], rs[x], rs[y], k - sum[ls[o]]);
 56         }
 57         sum[x] = sum[ls[x]] + sum[rs[x]];
 58         sum[y] = sum[ls[y]] + sum[rs[y]];
 59         return;
 60     }
 61     void out(int l, int r, int o) {
 62         if(!o || !sum[o]) return;
 63         if(l == r) {
 64             printf("%d ", r);
 65             return;
 66         }
 67         int mid = (l + r) >> 1;
 68         out(l, mid, ls[o]);
 69         out(mid + 1, r, rs[o]);
 70         return;
 71     }
 72 }
 73 
 74 /// ---------
 75 
 76 int fa[N], s[N][2], len[N], lpos[N], rpos[N], siz[N], type[N], root, tot, n, a[N];
 77 std::stack<int> Bin;
 78 int stk[N], top;
 79 
 80 inline void pushup(int x) {
 81     siz[x] = siz[s[x][0]] + siz[s[x][1]] + len[x];
 82     //printf("pushup [%d %d] %d + %d + %d \n", lpos[x], rpos[x], siz[s[x][0]], len[x], siz[s[x][1]]);
 83     if(!fa[x]) root = x;
 84     return;
 85 }
 86 
 87 inline void pushdown(int x) {
 88     return;
 89 }
 90 
 91 inline void rotate(int x) {
 92     int y = fa[x];
 93     int z = fa[y];
 94     bool f = (s[y][1] == x);
 95 
 96     fa[x] = z;
 97     if(z) {
 98         s[z][s[z][1] == y] = x;
 99     }
100     s[y][f] = s[x][!f];
101     if(s[x][!f]) {
102         fa[s[x][!f]] = y;
103     }
104     s[x][!f] = y;
105     fa[y] = x;
106 
107     pushup(y);
108     return;
109 }
110 
111 inline void splay(int x, int g = 0) {
112     int y = x;
113     stk[top = 1] = y;
114     while(fa[y]) {
115         y = fa[y];
116         stk[++top] = y;
117     }
118     while(top) {
119         pushdown(stk[top]);
120         top--;
121     }
122 
123     y = fa[x];
124     int z = fa[y];
125     while(y != g) {
126         if(z != g) {
127             (s[z][1] == y) ^ (s[y][1] == x) ?
128             rotate(x) : rotate(y);
129         }
130         rotate(x);
131         y = fa[x];
132         z = fa[y];
133     }
134     pushup(x);
135     return;
136 }
137 
138 void out(int x = root) {
139     pushdown(x);
140     if(s[x][0]) {
141         out(s[x][0]);
142     }
143     printf("[%d %d] ", lpos[x], rpos[x]);
144     printf("rt = %d : ", seg::rt[x]);
145     seg::out(1, n, seg::rt[x]);
146     puts("");
147     if(s[x][1]) {
148         out(s[x][1]);
149     }
150     return;
151 }
152 
153 inline int np(int l, int r, int f, int tp) {
154     int x;
155     if(Bin.size()) {
156         x = Bin.top();
157         seg::rt[x] = 0;
158         Bin.pop();
159     }
160     else x = ++tot;
161     fa[x] = f;
162     s[x][0] = s[x][1] = 0;
163     lpos[x] = l;
164     rpos[x] = r;
165     siz[x] = len[x] = r - l + 1;
166     type[x] = tp;
167     return x;
168 }
169 
170 inline int getRP() {
171     pushdown(root);
172     int p = s[root][1];
173     pushdown(p);
174     while(s[p][0]) {
175         p = s[p][0];
176         pushdown(p);
177     }
178     return p;
179 }
180 
181 inline int getLP() {
182     pushdown(root);
183     int p = s[root][0];
184     pushdown(p);
185     while(s[p][1]) {
186         p = s[p][1];
187         pushdown(p);
188     }
189     return p;
190 }
191 
192 inline int getPbyR(int k) {
193     k++;
194     int p = root;
195     while(1) {
196         //printf("p : [%d %d] %d -> [%d %d] %d  [%d %d] %d \n", lpos[p], rpos[p], siz[p], lpos[s[p][0]], rpos[s[p][0]], siz[s[p][0]], lpos[s[p][1]], rpos[s[p][1]], siz[s[p][1]]);
197         pushdown(p);
198         if(k <= siz[s[p][0]]) {
199             p = s[p][0];
200         }
201         else if(k <= siz[s[p][0]] + len[p]) {
202             break;
203         }
204         else {
205             k -= siz[s[p][0]] + len[p];
206             p = s[p][1];
207         }
208     }
209     /// p
210     splay(p);
211     return p;
212 }
213 
214 inline int split(int x, int k) { /* [lpos[x], k] [k + 1, rpos[x]] return left */
215     int A, B;
216     splay(x);
217     int y = getRP();
218     splay(y, x);
219     if(type[x] == 0) {
220         seg::split(seg::rt[x], A, B, k);
221         int z = np(lpos[x] + k, rpos[x], y, type[x]);
222         rpos[x] = lpos[x] + k - 1;
223         len[x] = rpos[x] - lpos[x] + 1;
224         seg::rt[z] = B;
225         seg::rt[x] = A;
226         s[y][0] = z;
227         pushup(y);
228         pushup(x);
229     }
230     else {
231         seg::split(seg::rt[x], A, B, len[x] - k);
232         int z = np(lpos[x] + k, rpos[x], y, type[x]);
233         rpos[x] = lpos[x] + k - 1;
234         len[x] = rpos[x] - lpos[x] + 1;
235         seg::rt[z] = A;
236         seg::rt[x] = B;
237         s[y][0] = z;
238         pushup(y);
239         pushup(x);
240     }
241     return x;
242 }
243 
244 void dfs(int x, int rt) {
245     if(s[x][0]) {
246         dfs(s[x][0], rt);
247     }
248     if(s[x][1]) {
249         dfs(s[x][1], rt);
250     }
251     if(x != rt) {
252         seg::rt[rt] = seg::merge(seg::rt[rt], seg::rt[x]);
253         Bin.push(x);
254     }
255     return;
256 }
257 
258 inline void Sort(int L, int R, int f) { /* 0 up  1 down */
259     int x = getPbyR(L);
260 
261     //printf("x %d [%d %d] y %d [%d %d] \n", x, lpos[x], rpos[x], y, lpos[y], rpos[y]);
262 
263     if(lpos[x] != L) {
264         x = split(x, L - lpos[x]);
265         splay(x);
266         x = getRP();
267     }
268     int y = getPbyR(R);
269     //printf("x %d [%d %d] y %d [%d %d] \n", x, lpos[x], rpos[x], y, lpos[y], rpos[y]);
270     if(rpos[y] != R) {
271         y = split(y, R - lpos[y] + 1);
272     }
273     // merge [x, y]
274     //printf("x %d [%d %d] y %d [%d %d] \n", x, lpos[x], rpos[x], y, lpos[y], rpos[y]);
275     splay(x);
276     int A = getLP();
277     splay(y);
278     int B = getRP();
279     splay(B);
280     splay(A, B);
281     /// s[A][1]
282     x = s[A][1];
283     dfs(x, x);
284     lpos[x] = L;
285     rpos[x] = R;
286     siz[x] = len[x] = R - L + 1;
287     type[x] = f;
288     s[x][0] = s[x][1] = 0;
289     pushup(A);
290     pushup(B);
291     return;
292 }
293 /*
294 5 5
295 1 2 3 4 5
296 1 2 3
297 1 4 5
298 1 1 4
299 0 2 5
300 0 3 4
301 1
302 ------------
303 */
304 inline int ask(int p) {
305     int x = getPbyR(p);
306     if(type[x] == 0) {
307         int k = p - lpos[x] + 1;
308         return seg::getKth(k, 1, n, seg::rt[x]);
309     }
310     else {
311         int k = p - lpos[x] + 1;
312         k = len[x] - k + 1;
313         return seg::getKth(k, 1, n, seg::rt[x]);
314     }
315 }
316 
317 int build(int l, int r, int f) {
318     int mid = (l + r) >> 1;
319     int x = np(mid, mid, f, 0);
320     if(mid && mid <= n) seg::insert(a[mid], 1, n, seg::rt[x]);
321     if(l < mid) s[x][0] = build(l, mid - 1, x);
322     if(mid < r) s[x][1] = build(mid + 1, r, x);
323     pushup(x);
324     return x;
325 }
326 
327 int main() {
328     int m;
329     scanf("%d%d", &n, &m);
330     for(int i = 1; i <= n; i++) {
331         scanf("%d", &a[i]);
332     }
333     /// build
334     root = build(0, n + 1, 0);
335 
336     //out(), puts("");
337 
338     for(int i = 1, f, l, r; i <= m; i++) {
339         scanf("%d%d%d", &f, &l, &r);
340         Sort(l, r, f);
341         //out(), puts("");
342     }
343     int q;
344     scanf("%d", &q);
345     int t = ask(q);
346     printf("%d\n", t);
347     return 0;
348 }
AC代码

这题调的时候splay出了大约10个锅,从没写过的线段树分裂一次写对......

线段树分裂,把前k小分成一个,后面分成另一个。实现类似fhqtreap,不过要新开节点。

 

转载于:https://www.cnblogs.com/huyufeifei/p/10623647.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值