zoukankan      html  css  js  c++  java
  • 2555: SubString

    2555: SubString

    链接

    题意:

      动态在末尾加入一个字符串,询问一个字符串出现了多少次。

    分析:

      如果没有动态加入,那么建出SAM后,求出parent树上,每个点|Right|,然后走一遍找到对应的点,这个点的Right集合的大小就是答案。

      求Right可以从叶子结点往上走一遍。

      考虑动态加入,那么会在parent树上,增加一点,并且支持加边删边,求一个点的权值,在一条到根的链上增加一个数,所以LCT维护parent树。

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cctype>
    #include<set>
    #include<queue>
    #include<vector>
    #include<map>
    using namespace std;
    typedef long long LL;
    
    inline int read() {
        int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
        for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
    }
    
    const int N = 1200005;
    
    struct LCT{
        int fa[N], ch[N][2], sk[N], top, tag[N], R[N];
        inline void add(int x,int v) { 
            if (x) R[x] += v, tag[x] += v; 
        }
        inline void pushdown(int x) { 
            if (tag[x]) add(ch[x][0], tag[x]), add(ch[x][1], tag[x]), tag[x] = 0; 
        }
        inline bool isroot(int x) { 
            return ch[fa[x]][0] != x && ch[fa[x]][1] != x; 
        }
        inline int son(int x) { 
            return ch[fa[x]][1] == x; 
        }
        inline void rotate(int x) {
            int y = fa[x], z = fa[y], c = son(y), b = son(x), a = ch[x][!b];
            if (!isroot(y)) ch[z][c] = x; fa[x] = z;
            ch[x][!b] = y; fa[y] = x;
            ch[y][b] = a; if (a) fa[a] = y;
        }
        inline void splay(int x) {
            top = 1, sk[1] = x;
            for (int i = x; !isroot(i); i = fa[i]) sk[++top] = fa[i];
            while (top) pushdown(sk[top --]);
            while (!isroot(x)) {
                int y = fa[x];
                if (isroot(y)) rotate(x);
                else {
                    if (son(x) == son(y)) rotate(y), rotate(x);
                    else rotate(x), rotate(x);
                }
            }
        }
        inline void access(int x) {
            for (int last = 0; x; last = x, x = fa[x]) {
                splay(x); ch[x][1] = last;  
            }
        }
        inline void link(int x,int y) { // 这是一棵有根树,每条边的方向确定(指向父节点),不需要makeroot,后面是取出这条链,打标记 
            fa[x] = y; access(y); splay(y); add(y, R[x]);
        }
        inline void cut(int x) { // x 和 fa[x] 断开,fa[x]的深度小,所以是x的左儿子 
            access(x); splay(x); add(ch[x][0], -R[x]);
            fa[ch[x][0]] = 0; ch[x][0] = 0; 
        }    
    }lct; 
    
    int ch[N][26], len[N], fa[N], Last = 1, Index = 1;
    void extend(int c) {
        int np = ++Index, p = Last; lct.R[np] = 1;
        for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
        if (!p) fa[np] = 1, lct.link(np, 1);
        else {
            int Q = ch[p][c];
            if (len[Q] == len[p] + 1) fa[np] = Q, lct.link(np, Q);
            else {
                int NQ = ++Index;
                fa[NQ] = fa[Q]; lct.link(NQ, fa[Q]);
                len[NQ] = len[p] + 1;
                memcpy(ch[NQ], ch[Q], sizeof ch[Q]);
                fa[Q] = fa[np] = NQ;
                lct.cut(Q); lct.link(Q, NQ); lct.link(np, NQ);
                for (; p && ch[p][c] == Q; p = fa[p]) ch[p][c] = NQ;
            }
        }
        Last = np;
    }
    void build(char *s,int len) {
        for (int i = 0; i < len; ++i) extend(s[i] - 'A');
    }
    int find(char *s,int len) {
        int now = 1;
        for (int i = 0; i < len; ++i) {
            now = ch[now][s[i] - 'A'];
            if (!now) return 0;
        }
        lct.splay(now);
        return lct.R[now];
    }
    void getstr(char *s,int x,int len) {
        for (int i = 0; i < len; ++i) {
            x = (x * 131 + i) % len;
            swap(s[i], s[x]);        
        }
    }
    char s[N], opt[10];
    int main() {
        int n = read(), L, lastans = 0, ans;
        scanf("%s", s);
        L = strlen(s);
        build(s, L);
        for (int i = 1; i <= n; ++i) {
            scanf("%s%s", opt, s);
            L = strlen(s);
            getstr(s, lastans, L);
            if (opt[0] == 'Q') {
                ans = find(s, L); lastans ^= ans;
                printf("%d
    ", ans); 
            }
            else build(s, L);
        }    
        return 0;
    }
  • 相关阅读:
    关于AFNetworking访问网络超时的设置
    【iOS程序启动与运转】- RunLoop个人小结
    iOS开发中常用到的加密方式
    iOS开发路线简述
    iOS中多线程的实现方案
    HTTP原理
    浅析无线定位技术
    iOS-MVVM设计模式
    打造强大的BaseModel(1):让Model自我描述
    介绍一个基于jQuery的Cookie操作插件
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10367106.html
Copyright © 2011-2022 走看看