【BZOJ 1056 1862】排名系统
Description
排名系统通常要应付三种请求:上传一条新的得分记录、查询某个玩家的当前排名以及返回某个区段内的排名记录。当某个玩家上传自己最新的得分记录时,他原有的得分记录会被删除。为了减轻服务器负担,在返回某个区段内的排名记录时,最多返回10条记录。
Input
第一行是一个整数n(n>=10)表示请求总数目。接下来n行,每行包含了一个请求。请求的具体格式如下: +Name Score 上传最新得分记录。Name表示玩家名字,由大写英文字母组成,不超过10个字符。Score为最多8位的正整数。 ?Name 查询玩家排名。该玩家的得分记录必定已经在前面上传。 ?Index 返回自第Index名开始的最多10名玩家名字。Index必定合法,即不小于1,也不大于当前有记录的玩家总数。
Output
对于?Name格式的请求,应输出一个整数表示该玩家当前的排名。对于?Index格式的请求,应在一行中依次输出从第Index名开始的最多10名玩家姓名,用一个空格分隔。
Sample Input
20
+ADAM 1000000 加入ADAM的得分记录
+BOB 1000000 加入BOB的得分记录
+TOM 2000000 加入TOM的得分记录
+CATHY 10000000 加入CATHY的得分记录
?TOM 输出TOM目前排名
?1 目前有记录的玩家总数为4,因此应输出第1名到第4名。
+DAM 100000 加入DAM的得分记录
+BOB 1200000 更新BOB的得分记录
+ADAM 900000 更新ADAM的得分记录(即使比原来的差)
+FRANK 12340000 加入FRANK的得分记录
+LEO 9000000 加入LEO的得分记录
+KAINE 9000000 加入KAINE的得分记录
+GRACE 8000000 加入GRACE的得分记录
+WALT 9000000 加入WALT的得分记录
+SANDY 8000000 加入SANDY的得分记录
+MICK 9000000 加入MICK的得分记录
+JACK 7320000 加入JACK的得分记录
?2 目前有记录的玩家总数为12,因此应输出第2名到第11名。
?5 输出第5名到第13名。
?KAINE 输出KAINE的排名
+ADAM 1000000 加入ADAM的得分记录
+BOB 1000000 加入BOB的得分记录
+TOM 2000000 加入TOM的得分记录
+CATHY 10000000 加入CATHY的得分记录
?TOM 输出TOM目前排名
?1 目前有记录的玩家总数为4,因此应输出第1名到第4名。
+DAM 100000 加入DAM的得分记录
+BOB 1200000 更新BOB的得分记录
+ADAM 900000 更新ADAM的得分记录(即使比原来的差)
+FRANK 12340000 加入FRANK的得分记录
+LEO 9000000 加入LEO的得分记录
+KAINE 9000000 加入KAINE的得分记录
+GRACE 8000000 加入GRACE的得分记录
+WALT 9000000 加入WALT的得分记录
+SANDY 8000000 加入SANDY的得分记录
+MICK 9000000 加入MICK的得分记录
+JACK 7320000 加入JACK的得分记录
?2 目前有记录的玩家总数为12,因此应输出第2名到第11名。
?5 输出第5名到第13名。
?KAINE 输出KAINE的排名
Sample Output
2
CATHY TOM ADAM BOB
CATHY LEO KAINE WALT MICK GRACE SANDY JACK TOM BOB
WALT MICK GRACE SANDY JACK TOM BOB ADAM DAM
4
CATHY TOM ADAM BOB
CATHY LEO KAINE WALT MICK GRACE SANDY JACK TOM BOB
WALT MICK GRACE SANDY JACK TOM BOB ADAM DAM
4
HINT
100%数据满足N<=250000
分析:
HASH表加上平衡树,这里的平衡树需要支持Insert(添加)、Delete(删除)、Rank(查询元素在树中的排名)和Select(找出第k大)。
需要注意的是,如果两个玩家的得分相同,则比较最后一次更新的时间,而不是加入玩家的时间。
这里用的是SBT。
1 // 2 // When I first coded it 3 // Just God and I could understand it 4 // But now 5 // Just God could 6 // 7 8 #include <cstdio> 9 #include <cstring> 10 11 #define HASHMOD 318931 12 #define MAXN 318931 13 14 int n, sco, len; 15 int prev[HASHMOD], last[HASHMOD]; 16 int score[HASHMOD], older[HASHMOD], num, old; 17 int father[MAXN], child[MAXN][2]; 18 int point[MAXN], size[MAXN], cnt, root; 19 char str[15], hash_value[HASHMOD][15]; 20 21 inline int Hash_Insert (int hash, int value) 22 { 23 num++; 24 prev[num] = last[hash]; 25 last[hash] = num; 26 score[num] = value; 27 older[num] = ++old; 28 strcpy (hash_value[num], str); 29 return num; 30 } 31 32 inline int Hash_Find (int hash) 33 { 34 for (int i = last[hash]; i; i = prev[i]) 35 if (strcmp (hash_value[i], str) == 0) 36 return i; 37 return -1; 38 } 39 40 void Rotate (int& f, int d) 41 { 42 int c = child[f][!d]; 43 child[f][!d] = child[c][d]; 44 child[c][d] = f; 45 size[c] = size[f]; 46 size[f] = size[child[f][0]] + size[child[f][1]] + 1; 47 f = c; 48 } 49 50 int NewNode (int p) 51 { 52 cnt++; 53 point[cnt] = p; 54 size[cnt] = 1; 55 return cnt; 56 } 57 58 void MainTain (int& t, int d) 59 { 60 if (!t) return; 61 if (size[child[child[t][d]][d]] > size[child[t][!d]]) 62 Rotate (t, !d); 63 else if (size[child[child[t][d]][!d]] > size[child[t][!d]]) 64 Rotate (child[t][d], d), Rotate (t, !d); 65 else return; 66 MainTain (child[t][0], 0); 67 MainTain (child[t][1], 1); 68 MainTain (t, 0); 69 MainTain (t, 1); 70 } 71 72 inline bool Cmp (int p, int t) 73 { 74 bool ret = score[p] < score[point[t]]; 75 if (score[p] == score[point[t]]) ret = older[p] >= older[point[t]]; 76 return ret; 77 } 78 79 void Insert (int& t, int p) 80 { 81 if (t == 0) t = NewNode (p); 82 else 83 { 84 size[t]++; 85 int d = Cmp (p, t); 86 Insert (child[t][d], p); 87 MainTain (t, d); 88 } 89 } 90 91 int Delete (int& t, int p) 92 { 93 int Ret; 94 size[t]--; 95 int d = Cmp (p, t); 96 if (p == point[t] || child[t][d] == 0) 97 { 98 Ret = point[t]; 99 if (child[t][0] && child[t][1]) 100 point[t] = Delete (child[t][0], p); 101 else t = child[t][0] + child[t][1]; 102 } else Ret = Delete (child[t][d], p); 103 return Ret; 104 } 105 106 void DelBoot (int p) 107 { 108 int i = Delete (root, p); 109 if (i != p) Insert (root, i); 110 } 111 112 inline void modify (int hash) 113 { 114 int id = Hash_Find (hash); 115 if (id < 0) id = Hash_Insert (hash, sco); 116 else DelBoot (id), score[id] = sco, older[id] = ++old; 117 Insert (root, id); 118 } 119 120 int Rank (int t, int p) 121 { 122 if (t == 0) return -1; 123 if (point[t] == p) return size[child[t][0]] + 1; 124 int d = Cmp (p, t); 125 if (d) return Rank (child[t][1], p) + size[child[t][0]] + 1; 126 return Rank (child[t][0], p); 127 } 128 129 int Select (int t, int k) 130 { 131 if (t == 0) return -1; 132 if (size[child[t][0]] == k - 1) return point[t]; 133 if (size[child[t][0]] > k - 1) return Select (child[t][0], k); 134 return Select (child[t][1], k - size[child[t][0]] - 1); 135 } 136 137 int main () 138 { 139 scanf ("%d", &n); 140 for (int i = 0; i < n; i++) 141 { 142 scanf ("%s", str); 143 len = strlen (str); 144 int hash = 0, a = 3785, b = 639; 145 for (int j = 1; j < len; j++) 146 { 147 hash = ((long long) hash * a + (str[j] == '?' ? '+' : str[j])) % HASHMOD; 148 a = a * b % HASHMOD; 149 } 150 if (str[0] == '+') 151 { 152 scanf ("%d", &sco); 153 modify (hash); 154 } else if (str[0] == '?') 155 { 156 if (str[1] > '9') 157 { 158 str[0] = '+'; 159 printf ("%d\n", Rank (root, Hash_Find (hash))); 160 } else 161 { 162 sco = 0; 163 for (int j = 1; j < len; j++) 164 sco = sco * 10 + str[j] - '0'; 165 for (int j = 0; j < 10 && sco <= size[root]; j++, sco++) 166 { 167 if (j > 0) printf (" "); 168 printf ("%s", hash_value[Select (root, sco)] + 1); 169 } 170 printf ("\n"); 171 } 172 } 173 } 174 }
Your eyes light up the world when you smile.