constint N = 3000010; int n, tt; int a[N], stk[N], ans[N];
intmain(){ scanf("%d", &n); for (int i = 1; i <= n; i ++) scanf("%d", &a[i]); for (int i = n; i >= 1; i --){ while (tt && a[i] >= a[stk[tt]]) tt --; if (tt) ans[i] = stk[tt]; else ans[i] = 0; stk[++ tt] = i; } for (int i = 1; i <= n; i ++) printf("%d ", ans[i]); return0; }
初始化:const int N = 100010; int son[N][26], cnt[N], idx;
insert操作;插入一个新字符串
1 2 3 4 5 6 7 8 9
voidinsert(char str[]){ int p = 0; for (int i = 0; str[i]; i ++){ int u = str[i] - 'a'; if (!son[p][u]) son[p][u] = ++idx; p = son[p][u]; } cnt[p] ++; }
query操作:查询字符串出现次数
1 2 3 4 5 6 7 8 9
intquery(char str[]){ int p = 0; for (int i = 0; str[i]; i ++){ int u = str[i] - 'a'; if (!son[p][u]) return0; p = son[p][u]; } return cnt[p]; }
voidinsert(char str[]){ //常规insert int p = 0; for (int i = 0; str[i]; i ++){ int u = get_number(str[i]); if (!son[p][u]) son[p][u] = ++ idx; p = son[p][u]; cnt[p] ++; } }
intquery(char str[]){ //query修改不多 int p = 0; for (int i = 0; str[i]; i ++){ int u = get_number(str[i]); if (!son[p][u]) return0; p = son[p][u]; } return cnt[p]; }
intmain(){ scanf("%d", &t); while (t --){ int n, q; scanf("%d%d", &n, &q); init(); while (n --){ scanf("%s", str); insert(str); } while (q --){ scanf("%s", str); printf("%d\n", query(str)); } } return0; }
自底部向上,对非叶子节点进行down操作,时间复杂度可缩减到
: for (int i = n / 2; i; i --) down(i); (下标从1开始)
down操作(根据大小关系交换节点,将上层节点向下交换)
1 2 3 4 5 6 7 8 9
voiddown(int u){ int t = u; if (u * 2 <= s && h[u * 2] < h[t]) t = u * 2; if (u * 2 + 1 <= s && h[u * 2 + 1] < h[t]) t = u * 2 + 1; if (u != t){ heap_swap(u, t); //需要记录其他信息时额外定义函数,无需记录时swap即可 down(t); } }
up操作(根据大小关系交换节点,将下层节点向上交换)
1 2 3 4 5 6
voidup(int u){ while (u / 2 && h[u] < h[u / 2]){ heap_swap(u, u / 2); u >>= 1; } }
constint N = 1000010; int n, idx; //idx同时也是Heap的大小 int h[N];
voiddown(int u){ int t = u; if (2 * u <= idx && h[2 * u] < h[t]) t = 2 * u; if (2 * u + 1 <= idx && h[2 * u + 1] < h[t]) t = 2 * u + 1; if (u != t){ swap(h[u], h[t]); down(t); } }
voidup(int u){ while (u / 2 && h[u / 2] > h[u]) { swap(h[u], h[u >> 1]); u >>= 1; } }
//核心模块代码示例 constint N = 100003; int n, h[N], e[N], ne[N], idx;
voidinsert(int x){ int k = (x % N + N) % N; //+N是为了解决C++中负数取模还是负数的问题 e[idx] = x, ne[idx] = h[k], h[k] = idx ++; //查到单链表头部 }
voidfind(int x){ int k = (x % N + N) % N; for (int i = h[k]; i != -1; i = ne[i]){ //主函数将h的值初始化为1 if (e[i] == x){ puts("Yes"); return; } } puts("No"); }
开放寻址法
开两到三倍大小的哈希数组
,顺移寻找每个数对应的哈希数组的位置.
1 2 3 4 5 6 7 8 9 10 11 12
//核心模块代码示例 constint N = 200003, null = 0x3f3f3f3f; //初始化h int n, h[N];
intfind(int x){ int k = ((x % N) + N) % N; while (h[k] != null && h[k] != x){ k ++; if (k == N) k = 0; } return k; }