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的主要内容,如果未能解决你的问题,请参考以下文章

luoguP3391[模板]文艺平衡树(Splay) 题解

luoguP3369[模板]普通平衡树(Treap/SBT) 题解

「LuoguP3369」 模板普通平衡树 (用vector乱搞平衡树

luoguP6136 模板普通平衡树(数据加强版)

luoguP6136 模板普通平衡树(数据加强版)

luoguP4036 [JSOI2008]火星人 平衡树+hash