constint N = 1e5+10; char str[N]; // son表示子节点,idx是每个节点的索引,cnt记录以该点结尾的单词个数 int son[N][26], cnt[N], idx;
intinsert(char str[]){ // p表示父节点 int p = 0; for (int i = 0; str[i]; i++) { // u表示当前节点,减去'a'可以将字母映射为数字0~25 int u = str[i] - 'a'; // 如果子节点不存在,创建子节点(赋予子节点编号idx) if(!son[p][u]) son[p][u] = ++idx; // 往下一层走 p = son[p][u]; }
// 创建完成后,该点结尾的单词数量++ cnt[p]++; }
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]; }
constint N = 1e5 + 10; // p 数组指向该点的父节点的编号 int p[N];
// 寻找 x 的根节点,重要 !!! intfind(int x){ // 如果不为根节点,则令 x 的父节点为父节点的父节点 // 这样操作之后最终指向的就会是根节点 if (p[x] != x) p[x] = find(p[x]);
// 归的过程就是返回根节点的编号,这样该枝所有的数都指向根节点 return p[x]; }
intmain(){ int n, m; scanf("%d%d", &n, &m); // 初始化每个节点的父节点的编号为自己的编号 // 也就是初始时每一个节点都是自己的根节点 // 换一句话说,只有根节点的父节点是自己 for (int i = 0; i < n; i++) p[i] = i;
char op[2]; int a, b; while (m--) { scanf("%s%d%d", op, &a, &b); // 让编号为 a 的数的根节点的父节点为编号 b 的根节点,也就是把 a 接在 b 上 if (op[0] == 'M') p[find(a)] = find(b); else { // 如果 a 和 b 的根节点相同, 则在同一个树上 if (find(a) == find(b)) printf("Yes\n"); elseprintf("No\n"); } }
constint N = 1e5 + 10; int n; // h 即 heap,存储堆中数据 int h[N]; // ph 记录第 k 个创建的点的编号 // hp 记录该点指向的 ph 数组的下标 int ph[N], hp[N]; // heap_size 记录堆的大小,也就是最后一个点的编号 int heap_size, m;
// 交换函数不是简单的交换,要把映射的变量也交换 voidheap_swap(int a, int b){ // 交换编号为 a 和 b 的堆指向的 ph 数组(hp[a]是其下标) 所指向的数。 swap(ph[hp[a]], ph[hp[b]]); // 交换编号为 a 和 b 的堆指向的 ph 数组 swap(hp[a], hp[b]); // 交换编号为 a 和 b 的堆中的数 swap(h[a], h[b]); }
voiddown(int u){ // t记录最小点的编号 int t = u;
// 如果左子节点存在且更小 if (u * 2 <= heap_size && h[u * 2] < h[t]) t = u * 2; // 如果右子节点存在且更小 if (u * 2 + 1 <= heap_size && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
// 如果最小的数不是当前数 if (u != t) { // 交换两点 heap_swap(u, t); // 应满足越往上的点越小,如果换下去的数比它的子节点还大,就要再往下走 down(t); } }
voidup(int u){ // 确保父节点存在 u / 2 > 0,如果父节点更大,则交换 while (u / 2 && h[u / 2] > h[u]) { heap_swap(u / 2, u); // 原先编号为 u 的数被换上去了,这里要保证 u 时刻追踪这个数,直到 up 操作结束 u /= 2; } }
intmain(){ scanf("%d", &n);
string op; while (n--) { cin >> op; if (op == "I") { int x; scanf("%d", &x); // m 表示第几个插入的数 m++; // heap_size 记录堆的大小,也就是最后一个点的编号 heap_size++; // 插入的时候总是操作最后一个数 // 让最后一个数指向的 ph 数组的下标为 m,也就是记录了这个数是第几个插入的 hp[heap_size] = m; // 记录第 m 个插入的数的编号为 heap_size ph[m] = heap_size; // 给该点赋值 h[heap_size] = x; // 让改点往上走,找到自己的位置 up(heap_size); } elseif (op == "PM") { // 第一个点总是最小的点 printf("%d\n", h[1]); } elseif (op == "DM") { // 删除第一个点 // 先将第一个点与最后一个点交换 heap_swap(1, heap_size); // 堆的大小减1,也就是删除了最后一个点 heap_size--; // 再把换上来的这个点 down 下去 down(1); } elseif (op == "D") { int k; scanf("%d", &k); // 第 k 个创建的点的编号为 ph[k] 的值 k = ph[k]; // 先将该点和最后一个点交换(同理删除第 1 个点) heap_swap(k, heap_size); // 再删除最后一个点 heap_size--; // 最后把换上来的点 down 下去 up(k); down(k); } else { // 最后一个操作:修改第 k 个插入的数,将其变为 x int k, x; scanf("%d%d", &k, &x); // 第 k 个创建的点的编号为 ph[k] 的值 k = ph[k]; // 修改该点的值为 x h[k] = x; // 实际只会执行 down 或者 up,因为它不可能同时满足 down 的条件(比它的子节点大)又满足 up 的条件(比它的父节点小) up(k); down(k); } }