VIJOS P1647 不差钱 SBT
【描述】
同学们一起看了小品《不差钱》,LX神突发奇想,想***难一下十八居士,他让十八居士模拟一下点菜的过程。
【输入格式】
输入第一行为一个数price,表示价钱大于price的菜赵本山都不要。
以下几行表示点菜的过程,每行两个整数p,n
p=1 表示在菜谱中添加一个价格为n的菜,这是第i个1号命令,这个菜的编号就是i,
p=2 表示菜谱中第n号菜已卖完(但不代表菜谱中没有了这种菜),
p=3 表示赵本山点第n贵的菜。
输入文件以0结束。
菜的价格0<n<=10^6。
3种命令, 30%数据命令最多300次, 60%数据命令最多3000次, 100%数据命令最多100000次。
【输出格式】
对于每个p=3, 如果第n贵的菜价格高于price,则输出“Dui bu qi,Mei you.”。
如果第n贵的菜价格不高于price,且没有卖完,则输出“You.”然后输出价格" m Yuan.";
如果已卖完,则输出“Mei you. Zhe ge ke yi you. Zhe ge zhen mei you!”
【分析】
题目意思表达得比较明确,本题也很适合作为SBT的模板题。
菜的编号就是存在SBT静态数组中的下标,只要加一个是否empty的标记即可。
唯一稍微可能有点问题的是出现多个相同菜价的菜时的选择问题,一开始按照普通二叉树的写法写SBT的前趋后继,后来发现这样做其实是不严谨的,因为左右旋操作的存在,虽然一开始相等的数是插入到右边去,但是不能保证不会因为左旋而把父节点旋到左子树去了,所以最后只能保证左子树的值不大于根,右子树的值不小于根,相等值是完全没办法判断的。
......最后只好继续查找第n-1大、n-2大...第n+1大、第n+2大...直到找到不相等为止,O(k*logn)遍历一遍相等的数。
好在测试时间上好像还不错,不知道又没有更好的办法?
1 /* *********************************************** 2 MYID : Chen Fan 3 LANG : G++ 4 PROG : VIJOS1647 5 ************************************************ */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <algorithm> 11 12 using namespace std; 13 14 #define MAXN 100010 15 16 typedef struct sbtnod 17 { 18 int key,left,right,size; 19 bool empty; 20 } sbtnode; 21 int sbttail,sbt; 22 23 sbtnode tree[MAXN]; 24 25 void rrotate(int& t) 26 { 27 int k=tree[t].left; 28 if (!k) return ; 29 tree[t].left=tree[k].right; 30 tree[k].right=t; 31 tree[k].size=tree[t].size; 32 tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+1; 33 t=k; 34 } 35 36 void lrotate(int& t) 37 { 38 int k=tree[t].right; 39 if (!k) return ; 40 tree[t].right=tree[k].left; 41 tree[k].left=t; 42 tree[k].size=tree[t].size; 43 tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+1; 44 t=k; 45 } 46 47 void maintain(int& t,bool flag) 48 { 49 if (!t) return ; 50 if (!flag) 51 if (tree[tree[tree[t].left].left].size>tree[tree[t].right].size) rrotate(t); 52 else if (tree[tree[tree[t].left].right].size>tree[tree[t].right].size) 53 { 54 lrotate(tree[t].left); 55 rrotate(t); 56 } else return ; 57 else 58 if (tree[tree[tree[t].right].right].size>tree[tree[t].left].size) lrotate(t); 59 else if (tree[tree[tree[t].right].left].size>tree[tree[t].left].size) 60 { 61 rrotate(tree[t].right); 62 lrotate(t); 63 } else return ; 64 65 maintain(tree[t].left,false); 66 maintain(tree[t].right,true); 67 maintain(t,false); 68 maintain(t,true); 69 } 70 71 void insert(int& t,int v) 72 { 73 if (!t) 74 { 75 sbttail++; 76 tree[sbttail].key=v; 77 tree[sbttail].size=1; 78 tree[sbttail].empty=false; 79 t=sbttail; 80 } else 81 { 82 tree[t].size++; 83 if (v<tree[t].key) insert(tree[t].left,v); 84 else insert(tree[t].right,v); 85 maintain(t,v>=tree[t].key); 86 } 87 } 88 89 int select(int t,int k) 90 { 91 if (k==tree[tree[t].left].size+1) return t; 92 if (k<=tree[tree[t].left].size) return select(tree[t].left,k); 93 else return select(tree[t].right,k-1-tree[tree[t].left].size); 94 } 95 96 int main() 97 { 98 freopen("1.txt","r",stdin); 99 100 int pri; 101 scanf("%d",&pri); 102 103 sbt=0; 104 sbttail=0; 105 106 int p,n; 107 while(scanf("%d%d",&p,&n)==2) 108 { 109 switch(p) 110 { 111 case 1: 112 insert(sbt,n); 113 break; 114 case 2: 115 tree[n].empty=true; 116 break; 117 case 3: 118 n=sbttail-n+1; 119 int temp=select(sbt,n); 120 if (tree[temp].key>pri) printf("Dui bu qi,Mei you.\n"); 121 else 122 { 123 bool done=false; 124 if (!tree[temp].empty) 125 { 126 done=true; 127 printf("You. %d Yuan.\n",tree[temp].key); 128 } else 129 { 130 int pre,p=n; 131 while(p>1&&(!done)) 132 { 133 p--; 134 pre=select(sbt,p); 135 if (tree[pre].key<tree[temp].key) break; 136 if (!tree[pre].empty) 137 { 138 done=true; 139 printf("You. %d Yuan.\n",tree[temp].key); 140 } 141 } 142 int suc,s=n; 143 while(s<n&&(!done)) 144 { 145 s++; 146 suc=select(sbt,s); 147 if (tree[suc].key>tree[temp].key) break; 148 if (!tree[suc].empty) 149 { 150 done=true; 151 printf("You. %d Yuan.\n",tree[temp].key); 152 } 153 } 154 } 155 if (!done) printf("Mei you. Zhe ge ke yi you. Zhe ge zhen mei you!\n"); 156 } 157 } 158 } 159 160 return 0; 161 }