bzoj 1503: [NOI 2004]郁闷的出纳员
这道题整整搞了我5天。。。。用到了数列的插入,删除和查询第K大
写的第一道平衡树题。。可以用各种平衡树和线段树来写,不失为一道极佳的平衡树练手题(据说树状数组也可以??Orz)
一开始是用splay,splay网上的code大部分都用了指针我根本看不懂。
后来找葱娘的ACcode用数组写的才总算看懂一点。。我理解了一晚上,写了一上午,调了一下午加晚上。。
葱娘的代码就是神,一开始我还以为要用到区间修改,后面发现葱娘用一个变量记录增量就可以了(Orz!!)
附上单旋SPLAYcode,这道题数据比较水,双旋单旋差不多
1 /* 2 ID:WULALA 3 PROB:splay bzoj1503 4 LANG:C++ 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 #include <cmath> 10 #include <iostream> 11 #include <ctime> 12 #include <set> 13 #define N 100008 14 #define M 15 #define mod 16 #define mid(l,r) ((l+r) >> 1) 17 #define INF 0x7ffffff 18 using namespace std; 19 20 struct node 21 { 22 int l,r,f,key,s,v; 23 }tree[N]; 24 25 int n,m,root,delta,l,tot = 1; 26 27 inline void update(int x) 28 { 29 tree[x].s = tree[tree[x].l].s + tree[tree[x].r].s + 1; 30 } 31 32 inline void zig(int &x) 33 { 34 int y = tree[x].f; 35 int z = tree[y].f; 36 if (y == tree[z].l) tree[z].l = x; 37 else tree[z].r = x; 38 tree[x].f = z; 39 tree[y].l = tree[x].r; 40 tree[tree[x].r].f = y; 41 tree[x].r = y; 42 tree[y].f = x; 43 update(y); update(x); 44 if (y == root) root = x; 45 } 46 47 inline void zag(int &x) 48 { 49 int y = tree[x].f; 50 int z = tree[y].f; 51 if (y == tree[z].l) tree[z].l = x; 52 else tree[z].r = x; 53 tree[x].f = z; 54 tree[y].r = tree[x].l; 55 tree[tree[x].l].f = y; 56 tree[y].f = x; 57 tree[x].l = y; 58 update(y); update(x); 59 if (y == root) root = x; 60 } 61 62 void splay(int &x,int d) 63 { 64 while (tree[x].f != d) 65 { 66 if (tree[tree[x].f].l == x) zig(x); 67 else zag(x); 68 } 69 } 70 71 void insert(int k) 72 { 73 if (!root) 74 { 75 root = ++tot; 76 tree[tot].key = k; 77 tree[tot].s = 1; 78 return; 79 } 80 int p = root,z; 81 while(p) 82 { 83 z = p; 84 ++tree[p].s; 85 if (k < tree[p].key) p = tree[p].l; 86 else p = tree[p].r; 87 } 88 if (tree[z].key>k) tree[z].l = ++tot; 89 else tree[z].r = ++tot; 90 tree[tot].key = k; 91 tree[tot].s = 1; 92 tree[tot].f = z; 93 splay(tot,0); 94 } 95 96 int find(int x,int k) 97 { 98 if (k <= tree[tree[x].r].s) 99 return (find(tree[x].r,k)); 100 if (k == tree[tree[x].r].s+1) 101 return tree[x].key; 102 return find(tree[x].l,k-tree[tree[x].r].s-1); 103 } 104 105 int dec(int &x,int f) 106 { 107 if (!x) return 0; 108 int k; 109 if (tree[x].key + delta < m) 110 { 111 k = dec(tree[x].r,x) + tree[tree[x].l].s + 1; 112 tree[tree[x].r].s = tree[x].s-k; 113 x = tree[x].r; 114 tree[x].f = f; 115 } 116 else 117 { 118 k = dec(tree[x].l,x); 119 tree[x].s -= k; 120 } 121 return k; 122 } 123 124 int main() 125 { 126 // freopen("input.txt","r",stdin); 127 // freopen("output.txt","w",stdout); 128 scanf("%d%d",&n,&m); 129 while(n--) 130 { 131 char c[1]; 132 int k; 133 scanf("%s%d",&c,&k); 134 if (c[0] == 'I' && k >= m) insert(k - delta); 135 else if (c[0] == 'F') 136 printf("%d\n",k <= tree[root].s?find(root,k)+delta:-1); 137 else if (c[0] == 'A') 138 delta += k; 139 else if (c[0] == 'S') 140 {delta -= k; l+=dec(root,0);} 141 } 142 printf("%d\n",l); 143 return 0; 144 }
看了一下HZW的treap在较好情况下比我的快了3倍。。人家还会用线段树做。。好自卑。。我连随机函数都不会用(orz!!)
然后又用sbt写,sbt也是刚学,各种变参不会用,又调试了一下午加晚上,终于还是写出来了
葱娘说SBT是傻逼树(SBTree),我特么觉得是超变态(SuperBT),唉。。这就是神犇与蒟蒻的差距啊。。
喜闻乐见的贴代码
1 /* 2 ID:WULALA 3 PROB:SBT bzoj1503 4 LANG:C++ 5 */ 6 #include <cstdio> 7 #include <cstring> 8 #include <algorithm> 9 #include <cmath> 10 #include <iostream> 11 #include <ctime> 12 #include <set> 13 #define N 100008 14 #define M 15 #define mod 16 #define mid(l,r) ((l+r) >> 1) 17 #define INF 0x7ffffff 18 using namespace std; 19 20 int n,MIN,delta,cnt,tot,root; 21 22 struct WULALA 23 { 24 int l,r,s,v; 25 }p[N]; 26 27 void zig(int &x) 28 { 29 int y = p[x].l; 30 p[x].l = p[y].r; 31 p[y].r = x; 32 p[y].s = p[x].s; 33 p[x].s = p[p[x].l].s + p[p[x].r].s + 1; 34 x = y; 35 } 36 37 void zag(int &x) 38 { 39 int y = p[x].r; 40 p[x].r = p[y].l; 41 p[y].l = x; 42 p[y].s = p[x].s; 43 p[x].s = p[p[x].l].s + p[p[x].r].s + 1; 44 x = y; 45 } 46 47 void maintain(int &x,bool flag) 48 { 49 int l = p[x].l,r = p[x].r; 50 if (!flag) 51 { 52 if (p[p[l].l].s > p[r].s) 53 zig(x); 54 else if (p[p[l].r].s > p[r].s) 55 // zag(l),zig(x); 56 zag(p[x].l),zig(x);//x已改变,下同理; 57 else return ; 58 } 59 else 60 { 61 if (p[p[r].r].s > p[l].s) 62 zag(x); 63 else if (p[p[r].l].s > p[l].s) 64 zig(p[x].r),zag(x); 65 else return ; 66 } 67 // maintain(l,false); 68 // maintain(r,true); 69 maintain(p[x].l,false); 70 maintain(p[x].r,true);//x已改变 71 maintain(x,false); 72 maintain(x,true); 73 } 74 75 void insert(int &x,int k) 76 { 77 if (!x) 78 { 79 x = ++tot; 80 p[x].s = 1; 81 p[x].v = k; 82 } 83 else 84 { 85 p[x].s++;//!! 86 if (p[x].v > k) insert(p[x].l,k); 87 else insert(p[x].r,k); 88 maintain(x,k >= p[x].v); 89 } 90 } 91 92 int del(int &x) 93 { 94 int ans; 95 if (!x) return 0; 96 if (p[x].v + delta < MIN) 97 { 98 ans = p[p[x].l].s + 1 + del(p[x].r); 99 p[p[x].r].s = p[x].s - ans; 100 x = p[x].r; 101 } 102 else 103 { 104 ans = del(p[x].l); 105 p[x].s -= ans; 106 } 107 return ans; 108 } 109 110 int find(int x,int k) 111 { 112 if (p[p[x].r].s >= k) return find(p[x].r,k); 113 else if (p[p[x].r].s == k - 1) return p[x].v; 114 else return find(p[x].l,k - p[p[x].r].s - 1); 115 } 116 117 void debug() 118 { 119 printf("%d\n",root); 120 for (int i = cnt+1;i <= tot;i++) 121 { 122 printf("%d %d %d %d\n",p[i].l,p[i].r,p[i].s,p[i].v); 123 } 124 } 125 126 int main() 127 { 128 scanf("%d%d",&n,&MIN); 129 while (n--) 130 { 131 char c[1]; int k; 132 scanf("%s%d",c,&k); 133 if (c[0] == 'I' && k >= MIN) 134 insert(root,k-delta); 135 else if (c[0] == 'A') 136 delta += k; 137 else if (c[0] == 'S') 138 delta -= k,cnt += del(root); 139 else if (c[0] == 'F') 140 printf("%d\n",k <= p[root].s?find(root,k)+delta:-1); 141 // debug(); 142 } 143 printf("%d\n",cnt); 144 return 0; 145 }