luoguP4715 [英语]Z语言 平衡树+hash
Posted reverymoon
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luoguP4715 [英语]Z语言 平衡树+hash相关的知识,希望对你有一定的参考价值。
显然只能有$hash$来做....
我们需要一个东西来维护$sum i * seed^{rank[i]}$
很自然地联想到平衡树
如果以序列下标建立一棵平衡树,那么无法处理
因此,可以以权值为下标建立一棵平衡树,把$rank[i]$拆分成若干个$sz[ls] + 1$即可维护
具体而言,记$pos[i]$表示$i$号节点的位置,$sum[i]$表示平衡树中$i$号节点的子树形成的$hash$值
那么,$sum[i] = pos[i] * seed^{sz[ls] + 1} + sum[ls] + sum[rs] * seed^{sz[ls] + 1}$
首先预处理出所有$A$串的$hash$值,存进$map$中
处理时,注意$[1, m]$和$[2, m + 1]$的串在平衡树中的$hash$值会有一个增量的区别
由于元素两两不同,因此可以确定增量为$sum seed^i$
之后,每次动态地维护$B$串的$hash$值,查询即可
下面的代码由于插入了$-1$,因此更新时略有不同...
复杂度$O(n log n)$
#include <map> #include <cstdio> #include <cstring> using namespace std; #define ll long long #define ri register int #define ull unsigned long long #define rep(io, st, ed) for(ri io = st; io <= ed; io ++) #define drep(io, ed, st) for(ri io = ed; io >= st; io --) #define gc getchar inline int read() { int p = 0; char c = gc(); while(c > ‘9‘ || c < ‘0‘) c = gc(); while(c >= ‘0‘ && c <= ‘9‘) p = p * 10 + c - ‘0‘, c = gc(); return p; } const int sid = 500050; const int seed = 19260817; ll val[sid]; map <ull, int> ans; int n, m, q, rt, id, A[sid], B[sid]; ull pos[sid], sum[sid], wei[sid]; int s[sid][2], sz[sid], fa[sid]; inline bool isrc(int o) { return s[fa[o]][1] == o; } inline void upd(int o) { int ls = s[o][0], rs = s[o][1]; sz[o] = sz[ls] + sz[rs] + 1; sum[o] = wei[sz[ls]] * pos[o] + sum[ls] + wei[sz[ls] + 1] * sum[rs]; } inline void rotate(int o) { int f = fa[o], g = fa[f]; int ro = isrc(o), rf = isrc(f); fa[o] = g; if(g) s[g][rf] = o; s[f][ro] = s[o][ro ^ 1]; fa[f] = o; fa[s[o][ro ^ 1]] = f; s[o][ro ^ 1] = f; upd(f); upd(o); } inline void splay(int o, int tar) { while(fa[o] != tar) { int f = fa[o], g = fa[f]; if(g != tar) rotate(isrc(o) == isrc(f) ? f : o); rotate(o); } if(!tar) rt = o; } inline void insert(ll v, int w) { int o = rt, f = 0; while(o) f = o, o = s[o][v > val[o]]; o = ++ id; if(f) s[f][v > val[f]] = o; fa[o] = f; sz[o] = 1; val[o] = v; pos[o] = w; sum[o] = w; splay(o, 0); } inline void find(ll v) { int o = rt; while(s[o][v > val[o]] && val[o] != v) o = s[o][v > val[o]]; splay(o, 0); } inline void erase(int v) { find(v); int pre = s[rt][0], suf = s[rt][1]; while(s[pre][1]) pre = s[pre][1]; while(s[suf][0]) suf = s[suf][0]; splay(pre, 0); splay(suf, pre); s[suf][0] = 0; if(suf) upd(suf); if(pre) upd(pre); } inline void Hash() { ull exa = 0; wei[0] = 1; rep(i, 1, m + 5) wei[i] = wei[i - 1] * seed; rep(i, 1, m) exa += wei[i]; insert(-1, 0); insert(2147483648, 0); rep(i, 1, m) insert(A[i], i); rep(i, m, n) { ans[sum[rt] - exa * (i - m)] ++; if(i == n) break; erase(A[i - m + 1]); insert(A[i + 1], i + 1); } rt = 0; rep(i, 1, id) { s[i][0] = s[i][1] = sz[i] = 0; val[i] = sum[i] = fa[i] = 0; } id = 0; } int main() { n = read(); m = read(); q = read(); rep(i, 1, n) A[i] = read(); Hash(); insert(-1, 0); insert(2147483648, 0); rep(i, 1, m) B[i] = read(); rep(i, 1, m) insert(B[i], i); rep(i, 1, q) { int x = read(), c = read(); erase(B[x]); insert(B[x] = c, x); printf("%d ", ans[sum[rt]]); } return 0; }
以上是关于luoguP4715 [英语]Z语言 平衡树+hash的主要内容,如果未能解决你的问题,请参考以下文章
luoguP3369[模板]普通平衡树(Treap/SBT) 题解