Trie树
说明:
son中的第一个维度并不是表示层数,就只是表示有N个结点
cnt[k]表示,以k结点作为结尾的字符串的个数
idx表示当前操作结点/*Trie树 —— 模板题 AcWing 835. Trie字符串统计*/ int son[N][26], cnt[N], idx; // 0号点既是根节点,又是空节点 // son[][]存储树中每个节点的子节点 // cnt[]存储以每个节点结尾的单词数量 // 插入一个字符串 void insert(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] ++ ; } // 查询字符串出现的次数 int query(char *str) { int p = 0; for (int i = 0; str[i]; i ++ ) { int u = str[i] - 'a'; if (!son[p][u]) return 0; p = son[p][u]; } return cnt[p]; }
并查集
(1)朴素并查集
int p[N]; //存储每个点的祖宗节点 // 返回x的祖宗节点 int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } // 初始化,假定节点编号是1~n for (int i = 1; i <= n; i ++ ) p[i] = i; // 合并a和b所在的两个集合: p[find(a)] = find(b);
(2)维护size的并查集:
int p[N], size[N]; //p[]存储每个点的祖宗节点, size[]只有祖宗节点的有意义,表示祖宗节点所在集合中的点的数量 // 返回x的祖宗节点 int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; } // 初始化,假定节点编号是1~n for (int i = 1; i <= n; i ++ ) { p[i] = i; size[i] = 1; } // 合并a和b所在的两个集合: size[find(b)] += size[find(a)]; p[find(a)] = find(b);
(3)维护到祖宗节点距离的并查集
int p[N], d[N]; //p[]存储每个点的祖宗节点, d[x]存储x到p[x]的距离 // 返回x的祖宗节点 int find(int x) { if (p[x] != x) { int u = find(p[x]); d[x] += d[p[x]]; p[x] = u; } return p[x]; } // 初始化,假定节点编号是1~n for (int i = 1; i <= n; i ++ ) { p[i] = i; d[i] = 0; } // 合并a和b所在的两个集合: p[find(a)] = find(b); d[find(a)] = distance; // 根据具体问题,初始化find(a)的偏移量
堆
// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1 // ph[k]存储第k个插入的点在堆中的位置 // hp[k]存储堆中下标是k的点是第几个插入的 int h[N], ph[N], hp[N], size; // 交换两个点,及其映射关系 void heap_swap(int a, int b) { swap(ph[hp[a]],ph[hp[b]]); swap(hp[a], hp[b]); swap(h[a], h[b]); } void down(int u) { int t = u; if (u * 2 <= size && h[u * 2] < h[t]) t = u * 2; if (u * 2 + 1 <= size && h[u * 2 + 1] < h[t]) t = u * 2 + 1; if (u != t) { heap_swap(u, t); down(t); } } void up(int u) { while (u / 2 && h[u] < h[u / 2]) { heap_swap(u, u / 2); u >>= 1; } } // O(n)建堆 for (int i = n / 2; i; i -- ) down(i); //crud string op;cin>>op; if(op=="I") { int x;cin>>x;++cnt;++id; h[cnt]=x;//将x放入堆的最后,然后向上调整 hp[cnt]=id,ph[id]=cnt; up(cnt); } else if(op=="PM")cout<<h[1]<<endl; else if(op=="DM") { heap_swap(1,cnt);cnt--; down(1); } else if(op=="D") {//首先,需要得到第k个插入的数在堆p[]中的下标,ph int k;cin>>k; int index=ph[k];//从k指向index heap_swap(index,cnt);cnt--; down(index);up(index);//实际上也只会执行一个. } else if(op=="C") {//首先,需要得到第k个插入的数在堆p[]中的下标,ph int k,x;cin>>k>>x; int index=ph[k]; h[index]=x;//细心:是通过h[index]修改值 down(index);up(index); }
h[x] 表示树中位置 x 的元素
ph[k] = x 表示第 k 个插入的元素在树中存放的位置 x
此时如果要交换 ph 中的两个元素需要知道树中位置 x 是第几个被插入的, 于是便引入了数组 hp
hp[x] = k 表示树中位置 x 存放的为第 k 个插入的元素