HDU 4006 The kth great number 优先队列、平衡树模板题(SBT)
The kth great number
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65768/65768 K (Java/Others)
【Problem Description】
Xiao Ming and Xiao Bao are playing a simple Numbers game. In a round Xiao Ming can choose to write down a number, or ask Xiao Bao what the kth great number is. Because the number written by Xiao Ming is too much, Xiao Bao is feeling giddy. Now, try to help Xiao Bao.
【Input】
There are several test cases. For each test case, the first line of input contains two positive integer n, k. Then n lines follow. If Xiao Ming choose to write down a number, there will be an " I" followed by a number that Xiao Ming will write down. If Xiao Ming choose to ask Xiao Bao, there will be a "Q", then you need to output the kth great number.
【Output】
The output consists of one integer representing the largest number of islands that all lie on one line.
【Sample Input】
8 3 I 1 I 2 I 3 Q I 5 Q I 4 Q
【Sample Output】
1 2 3
【Hint】
Xiao Ming won't ask Xiao Bao the kth great number when the number of the written number is smaller than k. (1=<k<=n<=1000000).
【题意】
给出一系列操作:
1.记录一个数;2.求第k小的数
【分析】
解法一、
题目每次询问的只是其中的一个数,这种情况下用一个堆来维护所有数的集合即可。
而且本题的k是一个固定值,因此只需要一个小根堆即可;若k不是一个固定值,则需要一个小根堆配合大根堆共同完成。
堆可以用STL中的优先队列来代替。
创建一个小根堆并向其加入数据,若堆中的数量大于k则弹出堆顶元素,始终保持整个堆中只有k个元素。遇到询问时,读取堆顶元素。
1 /* *********************************************** 2 MYID : Chen Fan 3 LANG : G++ 4 PROG : HDU4006 5 ************************************************ */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <algorithm> 11 #include <queue> 12 13 using namespace std; 14 15 struct cmp 16 { 17 bool operator()(int x,int y) 18 { 19 return x>y; 20 } 21 }; 22 23 int main() 24 { 25 //freopen("1.txt","r",stdin); 26 //freopen("std.txt","w",stdout); 27 28 int n,k; 29 30 while(scanf("%d%d",&n,&k)==2) 31 { 32 priority_queue<int,vector<int>,cmp>q; 33 char c; 34 for (int i=1;i<=n;i++) 35 { 36 c=getchar(); 37 while(c!='I'&&c!='Q') 38 { 39 c=getchar(); 40 } 41 if (c=='I') 42 { 43 int now; 44 scanf("%d",&now); 45 q.push(now); 46 if (q.size()>k) q.pop(); 47 } else 48 { 49 printf("%d\n",q.top()); 50 } 51 } 52 } 53 54 return 0; 55 }
解法二、
本题可作为平衡树模板题,虽然因为有点大材小用内存占用比较大,而且时间上并没有太大优势。
动态维护一棵平衡树,求k大值。
以下采用Size Balanced Tree完成:
1 /* *********************************************** 2 MYID : Chen Fan 3 LANG : G++ 4 PROG : HDU4006_SBT 5 ************************************************ */ 6 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring> 10 #include <algorithm> 11 12 using namespace std; 13 14 #define MAXN 1000010 15 16 typedef struct sbtnod 17 { 18 int key,left,right,size; 19 } sbtnode; 20 int sbttail,sbt; 21 22 sbtnode tree[MAXN]; 23 24 void rrotate(int& t) 25 { 26 int k=tree[t].left; 27 if (!k) return ; 28 tree[t].left=tree[k].right; 29 tree[k].right=t; 30 tree[k].size=tree[t].size; 31 tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+1; 32 t=k; 33 } 34 35 void lrotate(int& t) 36 { 37 int k=tree[t].right; 38 if (!k) return ; 39 tree[t].right=tree[k].left; 40 tree[k].left=t; 41 tree[k].size=tree[t].size; 42 tree[t].size=tree[tree[t].left].size+tree[tree[t].right].size+1; 43 t=k; 44 } 45 46 void maintain(int& t,bool flag) 47 { 48 if (!t) return ; 49 if (!flag) 50 if (tree[tree[tree[t].left].left].size>tree[tree[t].right].size) rrotate(t); 51 else if (tree[tree[tree[t].left].right].size>tree[tree[t].right].size) 52 { 53 lrotate(tree[t].left); 54 rrotate(t); 55 } else return ; 56 else 57 if (tree[tree[tree[t].right].right].size>tree[tree[t].left].size) lrotate(t); 58 else if (tree[tree[tree[t].right].left].size>tree[tree[t].left].size) 59 { 60 rrotate(tree[t].right); 61 lrotate(t); 62 } else return ; 63 64 maintain(tree[t].left,false); 65 maintain(tree[t].right,true); 66 maintain(t,false); 67 maintain(t,true); 68 } 69 70 void insert(int& t,int v) 71 { 72 if (!t) 73 { 74 sbttail++; 75 tree[sbttail].key=v; 76 tree[sbttail].size=1; 77 t=sbttail; 78 } else 79 { 80 tree[t].size++; 81 if (v<tree[t].key) insert(tree[t].left,v); 82 else insert(tree[t].right,v); 83 maintain(t,v>=tree[t].key); 84 } 85 } 86 87 int del(int& t,int v) 88 { 89 int ret; 90 tree[t].size--; 91 if (v==tree[t].key||(v<tree[t].key&&tree[t].left==0)||(v>tree[t].key&&tree[t].right==0)) 92 { 93 ret=tree[t].key; 94 if (tree[t].left==0||tree[t].right==0) t=tree[t].left+tree[t].right;// 95 else tree[t].key=del(tree[t].left,tree[t].key+1); 96 } else 97 { 98 if (v<tree[t].key) ret=del(tree[t].left,v); 99 else ret=del(tree[t].right,v); 100 } 101 return ret; 102 } 103 104 int select(int t,int k) 105 { 106 if (k==tree[tree[t].left].size+1) return t; 107 if (k<=tree[tree[t].left].size) return select(tree[t].left,k); 108 else return select(tree[t].right,k-1-tree[tree[t].left].size); 109 } 110 111 int main() 112 { 113 //freopen("1.txt","r",stdin); 114 //freopen("st.txt","w",stdout); 115 116 int n,k; 117 while(scanf("%d%d",&n,&k)==2) 118 { 119 memset(tree,0,sizeof(tree)); 120 sbttail=0; 121 sbt=0; 122 123 char c; 124 for (int i=1;i<=n;i++) 125 { 126 c=getchar(); 127 while(c!='I'&&c!='Q') 128 { 129 c=getchar(); 130 } 131 int now; 132 if (c=='I') 133 { 134 scanf("%d",&now); 135 insert(sbt,now); 136 } else 137 { 138 now=select(sbt,sbttail-k+1); 139 printf("%d\n",tree[now].key); 140 } 141 } 142 } 143 144 return 0; 145 }
Do Cool Things That Matter!