zoukankan      html  css  js  c++  java
  • 4556: [Tjoi2016&Heoi2016]字符串

    4556: [Tjoi2016&Heoi2016]字符串

    链接

    分析:

      首先可以二分这个长度。此时需要判断是否存在一个以b结尾的前缀,满足与[c,d]的lcp大于等于mid。

      如果我们把串翻转,那么就是判断是否存在一个以b开始的后缀,这样可以建出SAM,线段树维护每个点的right集合。此时在从包含[1,b]这个状态的点沿着parent树往上跳,那么长度会减少,相应的right集合会变大,于是可以跳到第一个长度满足的点,right集合也是满足的点中最大的,看这个点中是否存在[a,b-mid+1]的位置。

      SA的做法:求出height数组,二分一个长度mid,找到[c,d]的rnk设为p,从p往左往右找满足lcp长度都大于等于mid的区间[l,r],然后判断[l,r]中是否在[a,b-mid+1]中出现过。

    代码: 

    #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 = 200005;
    
    int ls[N * 20], rs[N * 20], Root[N], pos[N], ch[N][26], len[N], fa[N], tmp[N], xl[N], f[N][20];
    int TreeIndex, Index = 1, Last = 1, n;
    char s[N];
    
    void Insert(int l,int r,int &now,int p) {
        now = ++TreeIndex;
        if (l == r) return ;
        int mid = (l + r) >> 1;
        if (p <= mid) Insert(l, mid, ls[now], p);
        else Insert(mid + 1, r, rs[now], p);
    }
    int query(int l,int r,int now,int L,int R) {
        if (!now) return 0;
        if (L <= l && r <= R) return 1;
        int mid = (l + r) >> 1;
        if (L <= mid && query(l, mid, ls[now], L, R)) return 1;
        if (R > mid && query(mid + 1, r, rs[now], L, R)) return 1;
        return 0;
    }
    int Merge(int x,int y) {
        if (!x || !y) return x + y;
        int z = ++TreeIndex;
        ls[z] = Merge(ls[x], ls[y]);
        rs[z] = Merge(rs[x], rs[y]);
        return z;
    }
    void extend(int c,int i) {
        int np = ++Index, p = Last; pos[i] = np; // pos[i] = np; !!!!! 
        len[np] = len[p] + 1;
        for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
        if (!p) fa[np] = 1;
        else {
            int q = ch[p][c];
            if (len[q] == len[p] + 1) fa[np] = q;
            else {
                int nq = ++Index;
                memcpy(ch[nq], ch[q], sizeof(ch[q]));
                fa[nq] = fa[q];
                fa[np] = fa[q] = nq;
                len[nq] = len[p] + 1;
                for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
            }
        }
        Last = np;
        Insert(1, n, Root[np], i);
    }
    bool check(int mid,int x,int l,int r) {
        for (int i = 19; ~i; --i) if (len[f[x][i]] >= mid) x = f[x][i];
        return query(1, n, Root[x], l, r);
    }
    int main() {
        n = read();int m = read();
        scanf("%s", s + 1);
        reverse(s + 1, s + n + 1);
        for (int i = 1; i <= n; ++i) extend(s[i] - 'a', i); 
        for (int i = 1; i <= Index; ++i) tmp[len[i]] ++;
        for (int i = 1; i <= n; ++i) tmp[i] += tmp[i - 1];
        for (int i = Index; i >= 1; --i) xl[tmp[len[i]]--] = i;
        for (int i = Index; i > 1; --i) {
            int x = xl[i];
            Root[fa[x]] = Merge(Root[fa[x]], Root[x]);
        }
        for (int i = 1; i <= Index; ++i) f[i][0] = fa[i];
        for (int j = 1; j <= 19; ++j)     
            for (int i = 1; i <= Index; ++i) f[i][j] = f[f[i][j - 1]][j - 1];
        while (m --) {
            int a = n - read() + 1, b = n - read() + 1, c = n - read() + 1, d = n - read() + 1;
            swap(a, b); swap(c, d);
            int l = 1, r = min(d - c + 1, b - a + 1), ans = 0;
            while (l <= r) {
                int mid = (l + r) >> 1;
                if (check(mid, pos[d], a + mid - 1, b)) ans = mid, l = mid + 1;
                else r = mid - 1;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    React之JSX语法
    Visual Studio Code 使用 Typings 实现智能提示功能
    React.js 之hello word
    Linux命令详解-cd
    Linux命令详解-ls
    linux常用命令
    LINUX系统配置相关
    netsh
    Visual Studio
    乘法算术表
  • 原文地址:https://www.cnblogs.com/mjtcn/p/10533878.html
Copyright © 2011-2022 走看看