bzoj 4545 DQS 的 Trie

老年选手不会 SAM 也不会 LCT 系列

我的数据结构好菜啊 qnq

 

一颗 Trie 树,$q$ 次询问,每次可以是:

1.求这棵树上本质不同的子串数量

2.插入一个子树,保证总大小不超过 $100000$

3.询问一个字符串在 Trie 树上出现过多少次,保证所有询问串总长度不超过 $100000$

 

sol:

第一问显然就是个广义 SAM,可以在每次 extend 的时候顺便算出来

第二问和第三问要求动态维护 parent 树的子树 size,差分一下就变成了链加和单点查询,LCT 维护一下即可

 

注意的几个细节:

如果你要匹配一个整串,串在 SAM 上跑的时候是直接走 Trans 边,不跳 parent

(注意区别于,如果你要匹配一个串的子串,在 SAM 上跑的时候要跳 parent ,注意这两个不一样

LCT 的 link 和 cut,如果你使用的是不 makeroot 的偷懒写法,是不满足交换律的,一定都是一个方向(从上往下 link / cut)

为什么我不 makeroot 啊(平时啥都敢写系列

#include <bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
    int x = 0,f = 1; char ch = getchar();
    for(; !isdigit(ch); ch = getchar())if(ch == '-') f = -f;
    for(; isdigit(ch); ch = getchar())x = 10 * x + ch - '0';
    return x * f;
}
const int maxn = 400010;
#define ls ch[x][0]
#define rs ch[x][1]
char s[maxn];
int n, node[maxn];
int ch[maxn][2], fa[maxn], tag[maxn], val[maxn], st[maxn], top;
inline int isroot(int x) { return (ch[fa[x]][0] != x) && (ch[fa[x]][1] != x); }
inline void rotate(int x) {
    int y = fa[x], z = fa[y];
    int l = (ch[y][1] == x), r = l ^ 1;
    if(!isroot(y)) ch[z][ch[z][1] == y] = x;
    fa[x] = z; fa[ch[x][r]] = y; fa[y] = x;
    ch[y][l] = ch[x][r]; ch[x][r] = y;
}
inline void pushdown(int x) {
    if(x && tag[x]) {
        if(ls) tag[ls] += tag[x], val[ls] += tag[x];
        if(rs) tag[rs] += tag[x], val[rs] += tag[x];
        tag[x] = 0;
    }
}
inline void splay(int x) {
    st[top = 1] = x;
    for(int i = x; !isroot(i); i = fa[i]) st[++top] = fa[i];
    for(int i = top; i; i--) pushdown(st[i]);
    while(!isroot(x)) {
        int y = fa[x], z = fa[y];
        if(!isroot(y)) {
            if(ch[y][0] == x ^ ch[z][0] == y) rotate(x);
            else rotate(y);
        }
        rotate(x);
    }
}
inline void access(int x) {
    for(int y = 0; x; y = x, x = fa[x]) {
        splay(x);
        rs = y;
    }
}
inline void link(int x, int y) {
    fa[y] = x; //cerr << "link :" << x  << " " << y << endl;
    access(x); splay(x);
    val[x] += val[y];
    tag[x] += val[y];
}
inline void cut(int x, int y) {
    access(y); splay(y);  //cerr << "cut :" << x  << " " << y << endl;
    val[x] -= val[y];
    tag[x] -= val[y];
    fa[x] = 0; ch[y][0] = 0;
}
int tr[maxn][7], mxlen[maxn], pre[maxn], root, dfn;
LL ans;
int extend(int last, int c) {
    int p = last, np = last = ++dfn;
    mxlen[np] = mxlen[p] + 1;
    for(; p && !tr[p][c]; p = pre[p]) tr[p][c] = np;
    if(!p) pre[np] = root, link(root, np);
    else {
        int q = tr[p][c];
        if(mxlen[p] + 1 == mxlen[q]) pre[np] = q, link(q, np);
        else {
            int nq = ++dfn;
            mxlen[nq] = mxlen[p] + 1;
            pre[nq] = pre[q];
            link(pre[q], nq); 
            memcpy(tr[nq], tr[q], sizeof(tr[nq]));
            for(; p && tr[p][c] == q; p = pre[p]) tr[p][c] = nq;
            cut(pre[q], q);
            pre[np] = pre[q] = nq;
            link(pre[q], q);link(pre[np], np); 
        }
    }
    ans += ((LL)mxlen[np] - (LL)mxlen[pre[np]]);
    access(np); splay(np);
    val[np]++; tag[np]++;
//    cerr << np << endl;
    return np;
}
int first[maxn], to[maxn << 1], nx[maxn << 1], va[maxn], cnt;
int vis[maxn], clo, par[maxn];
inline void add(int u, int v, int w) {
    to[++cnt] = v;
    va[cnt] = w;
    nx[cnt] = first[u];
    first[u] = cnt;
}
void dfs(int x) {
    for(int i=first[x];i;i=nx[i]) {
        if(to[i] == par[x] || vis[to[i]] != clo) continue;
        par[to[i]] = x;
        node[to[i]] = extend(node[x], va[i]);
        dfs(to[i]);
    }
}
int run() {
    int now = root, len = strlen(s + 1);
    rep(i, 1, len) {
    //    while(now && !tr[now][s[i] - 'a']) now = pre[now];
        now = tr[now][s[i] - 'a'];
    }
    //cerr << now << endl;
    if(!now) return 0;
    access(now); splay(now);
    return val[now];
}
int main() {
    //freopen("8.in","r",stdin);
    //freopen("8oo.out","w",stdout);
    //freopen("8oo_err","w",stderr);
    root = ++dfn; node[1] = root;
    read(); n = read(); clo++; 
    rep(i, 2, n) {
        int u = read(), v = read();
        char ch; cin >> ch;
        add(u, v, ch - 'a'); add(v, u, ch - 'a');
        //cout << ch << endl;
        vis[u] = vis[v] = clo;
    } dfs(1);
    int q = read();
    while(q--) {
        int opt = read();
        if(opt == 1) printf("%lld\n", ans);
        else if(opt == 2) {
            int ri = read(), si = read(); clo++;
            rep(i, 2, si) {
                int u = read(), v = read();
                char ch; cin >> ch;
                add(u, v, ch - 'a'); add(v, u, ch - 'a');
                vis[u] = vis[v] = clo;
            } dfs(ri);
        }
        else if(opt == 3) {
            scanf("%s", s + 1);
            printf("%d\n", run());
        }
        //int xo = 0;
    //    rep(i, 1, n) xo ^= node[i];
        //cerr << xo << endl;
    }
}
View Code

 

posted @ 2019-03-30 11:28  探险家Mr.H  阅读(200)  评论(0编辑  收藏  举报