• 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
    ", 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
    ", run());
            }
            //int xo = 0;
        //    rep(i, 1, n) xo ^= node[i];
            //cerr << xo << endl;
        }
    }
    View Code
  • 相关阅读:
    CentOS6.2编译安装Nginx1.2.0
    mysql之主从复制篇
    CentOS6.2编译安装PHP5.4.0
    c# 多线程 编程
    QQ空间及邮箱验证码登录的校验方式及自动登录的解决方案
    C# 动态编译、动态执行、动态调试
    在Visual C#中用ListView显示数据记录
    推荐一个免费的HTTP抓包分析工具 Fiddler Web Debugger
    C#简繁体转换方法(Microsoft.Office.Interop.Word)
    C#读取字符串类型XML
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10626265.html
Copyright © 2020-2023  润新知