【思路】
题目要求实现对字符串和优先级的匹配、解除匹配、对比某优先级更高的字符串计数、撤销前面若干步这四种操作。
第一时间往平衡树方面想,但是并沒法做undo这个操作,做过这道题的同学告诉我:你想多了,这是两棵可持久化的Trie树。
下面是思考的总结:对于所有操作,必定需要记录下操作的结果,才能实现undo,而且满足这个条件时不应过分使用空间。我们可以用一个root指针数组保存每一步操作后的Trie树状态,如果undo x则意味着退到x个状态之前的那个状态,那么指针指向前面的root;如果是执行修改操作,则复制一下上一个状态再修改;如果是执行询问操作,则指针指向上一个root。Trie树在这里的作用,无非就是对应上字符串和优先级,对比某优先级大(也就是数值小)的字符串统计,时间复杂度为O(logN)级别。
【代码】
//************************************************************************ // File Name: main.cpp // Author: Shili_Xu // E-Mail: [email protected] // Created Time: 2018年02月02日 星期五 16时28分44秒 //************************************************************************ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 1e5 + 5; struct string_trie { int data; string_trie *child[26]; string_trie() { data = 0; for (int i = 0; i < 26; i++) child[i] = NULL; } string_trie(string_trie *another) { data = another->data; for (int i = 0; i < 26; i++) child[i] = another->child[i]; } }; struct binary_trie { int data; binary_trie *child[2]; binary_trie() { data = 0; child[0] = child[1] = NULL; } binary_trie(binary_trie *another) { data = another->data; child[0] = another->child[0]; child[1] = another->child[1]; } }; string_trie *string_root[MAXN]; binary_trie *binary_root[MAXN]; int q; void insert_string(int i, char *s, int x) { string_trie *p = string_root[i]; while (*s != '\0') { int id = *s - 'a'; if (p->child[id]) p->child[id] = new string_trie(p->child[id]); else p->child[id] = new string_trie(); p = p->child[id]; s++; if (*s == '\0') p->data = x; } } void insert_num(int i, int num, int x) { binary_trie *p = binary_root[i]; for (int j = 30; j >= 0; j--) { int id = (num >> j) & 1; if (p->child[id]) p->child[id] = new binary_trie(p->child[id]); else p->child[id] = new binary_trie(); p = p->child[id]; p->data += x; } } int search(int i, char *s) { string_trie *p = string_root[i]; while (*s != '\0') { int id = *s - 'a'; if (!p->child[id]) return 0; p = p->child[id]; s++; } return p->data; } int query(int i, int num) { binary_trie *p = binary_root[i]; int ans = 0; for (int j = 30; j >= 0; j--) { int id = (num >> j) & 1; if (id && p->child[0]) ans += p->child[0]->data; p = p->child[id]; } return ans; } int main() { string_root[0] = new string_trie(); binary_root[0] = new binary_trie(); scanf("%d", &q); for (int i = 1; i <= q; i++) { char mes[6], str[16]; int x; scanf("%s", mes); if (mes[0] == 's') { scanf("%s %d", str, &x); string_root[i] = new string_trie(string_root[i - 1]); binary_root[i] = new binary_trie(binary_root[i - 1]); int old = search(i, str); if (old != x) { insert_string(i, str, x); if (old) insert_num(i, old, -1); insert_num(i, x, 1); } } if (mes[0] == 'r') { scanf("%s", str); string_root[i] = new string_trie(string_root[i - 1]); binary_root[i] = new binary_trie(binary_root[i - 1]); int old = search(i, str); if (old) { insert_string(i, str, 0); insert_num(i, old, -1); } } if (mes[0] == 'q') { scanf("%s", str); string_root[i] = string_root[i - 1]; binary_root[i] = binary_root[i - 1]; int old = search(i, str); if (old) printf("%d\n", query(i, old)); else printf("-1\n"); } if (mes[0] == 'u') { scanf("%d", &x); string_root[i] = string_root[i - x - 1]; binary_root[i] = binary_root[i - x - 1]; } fflush(stdout); } return 0; }