hdu1890 伸展树区间翻转复习
来源:互联网 发布:手机交友软件排行 编辑:程序博客网 时间:2024/05/16 07:47
题意: 给你n个数,每次先输出第i大的数的位置(如果有多个,选下标小的那个),然后每次将第i个位置到第i大的数所在位置之间的数进行翻转。
思路:输入的数组可能有多个相同的值,我们可以进行两次排序把数组的值变为0---n-1(表示第几大)。
在建伸展树的时候我们可以顺便用pos[i]记录第i大的数的节点指针。
对于第i次操作,我们用flip记录翻转标记,每次先把第i大的节点pos[i]旋转到根,那么它的位置为i+左儿子的个数+1。然后左儿子打上翻转标记,最后删除根。
注意:下放懒惰标记时只要交换左右儿子的节点标号就可以了,也正因为这个原因,
下放函数的位置记得要放在没有引用任何左右儿子信息之前, 这跟区间其它操作最大的区别。
这次用指针写的,注意虚节点null 不能down, 因为null的左右儿子都为null 不能swap
#include <cstdio>#include <cstring>#include <algorithm>using namespace std;struct node;node *null, *root;struct node { node *c[2], *fa; int sz, id; bool flip; bool d() { return fa->c[1] == this; } void fix(int d, node *x) { c[d] = x; x->fa = this; } void rot() { node *y = fa, *z = y->fa; int f = d(); z->fix(y->d(), this); y->fix(f, c[!f]); fix(!f, y); y->up(); } void splay(node *g) { while(fa != g) { node *y = fa, *z = y->fa; z->down(), y->down(),down(); if(z == g) rot(); else if(y->d() == d()) y->rot(), rot(); else rot(),rot(); } up(); if(g == null) root = this; } void up() { sz = c[0]->sz + c[1]->sz+1; } void down() { if(this==null) return; if(flip) { c[0]->flip ^= 1; c[1]->flip ^= 1; swap(c[0], c[1]); flip = 0; } } void out() {//debug printf("v%d ls%d rs%d lsz%d rsz%d fa%d\n", id, c[0]->id, c[1]->id, c[0]->sz, c[1]->sz, fa->id); }};const int maxn = 100005;struct data { int val, id; bool operator<(const data &t) const { return id < t.id; }}a[maxn];bool cmp(const data &a, const data &b) { return a.val < b.val || (a.val == b.val && a.id < b.id);}struct splayTree { node mem[maxn]; int tot; node *pos[maxn]; node* newNode(node *fa=null) { node *x = &mem[tot]; x->c[0] = x->c[1] = null, x->fa = fa; x->sz = 1, x->id = tot++, x->flip = 0; return x; } void build(node *&x, int l, int r, node *fa) { if( l > r ) return; int m = (l + r) >> 1; x = newNode(fa); pos[a[m].val] = x; build(x->c[0], l, m-1, x); build(x->c[1], m+1, r, x); x->up(); } void rto(int k, node *g) { node *x = root; while(true) { x->down(); int v = x->c[0]->sz+1; if(v == k) break; if(k > v) { k -= v; x = x->c[1]; }else x = x->c[0]; } x->splay(g); } void init(int n) { tot = 0; int i, j; for(i = 0; i < n; i++) { scanf("%d", &a[i].val); a[i].id = i; } sort(a, a+n, cmp); for(i = 0; i < n; i++) a[i].val = i; sort(a, a+n); null = newNode(), null->sz = 0; root = null; build(root, 0, n-1, null); } void show(node *o) {//debug if(o==null) return; o->down(); o->out(); show(o->c[0]); show(o->c[1]); } void show() {//debug printf("root = %d\n", root->id); show(root); puts("~~~~~~"); } void work(int n) { int i; for(i = 0; i < n-1; i++) { pos[i]->splay(null); printf("%d ", root->c[0]->sz+i+1); root->down(); root->c[0]->flip^=1; root->c[0]->down(); if(root->c[0]!=null) { rto(root->c[0]->sz, root); node *x = root; root = x->c[0]; root->fa = null; root->fix(1, x->c[1]); }else { root = root->c[1]; root->fa = null; } root->up(); } printf("%d\n", n); }}spt;int main() { int i, j, n; while(~scanf("%d", &n) && n) { spt.init(n); spt.work(n); } return 0;}
3 0
- hdu1890 伸展树区间翻转复习
- Robotic Sort hdu1890 (伸展树翻转+删根)
- 伸展树 - hdu1890 Robotic Sort
- hdu 1890 伸展树区间翻转
- 3303 翻转区间 伸展树的解法
- CODEVS 1743(伸展树区间翻转)
- hdu 1890 区间翻转——伸展树
- hdu 1890伸展树(splay tree)区间翻转
- hdu3487 (splay伸展树 区间翻转,切割,插入)
- BZOJ 3223 浅谈SPLAY伸展树算法区间翻转
- hdu1890 Robotic Sort (splay+区间翻转单点更新)
- 序列神器伸展树 区间维护,区间提取,区间翻转的AC模板。
- 【伸展树】伸展树复习
- hdu1890 Robotic Sort Splay树,区间反转,lazy标记
- 伸展树解决区间问题
- hdu1890 Robotic Sort splay+懒惰标记+翻转
- hdu 4699 Editor 伸展树 treap复习
- 伸展树(插入、删除区间)BZOJ1269
- 等风来
- com.fasterxml.jackson.databind.ObjectMapper:可将object与json互转的工具
- Fibonacci数列
- CGContext画圆角矩形的函数
- java学习笔记 4种内部类小结
- hdu1890 伸展树区间翻转复习
- 书一封:黑客第一课
- RSA公司与EMC公司的故事
- 黑客第二课:脱屌第一步 —— Vim Fundamentals
- PLSQL复习笔记2014/2/16
- MyBatis学习
- Ubuntu下Firefox无法打开localhost:1158/em的解决方案
- 编辑文章 - 博客频道 - CSDN.NET
- 动态口令卡(口令牌)原理解读