zoukankan      html  css  js  c++  java
  • BZOJ 2865 字符串识别 | 后缀数组 线段树

    集训讲字符串的时候我唯一想出正解的题……

    链接

    BZOJ 2865

    题面

    给出一个长度为n (n <= 5e5) 的字符串,对于每一位,求包含该位的、最短的、在原串中只出现过一次的子串。

    题解

    “只出现过一次”,想到后缀数组,后缀数组可以求出以第i位开头的最短的在原串中只出现过一次的子串——它的长度是min(height[rank[i]], height[rank[i] + 1) + 1。

    所以我们枚举每个位置i,找到这个串,然后考虑它的贡献:

    对于这个串之内的位置,答案可以用这个串的长度更新;

    对于这个串右边的位置,串可以向右“延伸”直到包含该位置(延伸后的串显然也只出现过一次),所以答案可以用(该位置 - i + 1)来更新。

    这两个分别用线段树维护即可。

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    #define enter putchar('
    ')
    #define space putchar(' ')
    template <class T>
    void read(T &x){
        char c;
        bool op = 0;
        while(c = getchar(), c > '9' || c < '0')
    	if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
    	x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    const int N = 500005, INF = 0x3f3f3f3f;
    int n, sa[N], rnk[N], buf1[N], buf2[N], buc[N], height[N];
    int data[2][4*N], lazy[2][4*N], pos[N];
    char s[N];
    
    void pushdown(int h, int k){
        if(lazy[h][k] == INF) return;
        lazy[h][k << 1] = min(lazy[h][k << 1], lazy[h][k]);
        lazy[h][k << 1 | 1] = min(lazy[h][k << 1 | 1], lazy[h][k]);
        data[h][k << 1] = min(data[h][k << 1], lazy[h][k]);
        data[h][k << 1 | 1] = min(data[h][k << 1 | 1], lazy[h][k]);
        lazy[h][k] = INF;
    }
    void modify(int h, int k, int l, int r, int ql, int qr, int x){
        if(ql <= l && qr >= r){
            data[h][k] = min(data[h][k], x);
            lazy[h][k] = min(lazy[h][k], x);
            return;
        }
        int mid = (l + r) >> 1;
        if(ql <= mid) modify(h, k << 1, l, mid, ql, qr, x);
        if(qr > mid) modify(h, k << 1 | 1, mid + 1, r, ql, qr, x);
        data[h][k] = min(data[h][k << 1], data[h][k << 1 | 1]);
    }
    void pushdown_all(int k, int l, int r){
        if(l == r) return (void)(pos[l] = k);
        pushdown(0, k), pushdown(1, k);
        int mid = (l + r) >> 1;
        pushdown_all(k << 1, l, mid);
        pushdown_all(k << 1 | 1, mid + 1, r);
    }
    void suffix_sort(){
        int m = 128, *x = buf1, *y = buf2;
        for(int i = 0; i <= m; i++) buc[i] = 0;
        for(int i = 1; i <= n; i++) buc[x[i] = s[i]]++;
        for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
        for(int i = n; i; i--) sa[buc[x[i]]--] = i;
        for(int k = 1, p = 0; k <= n && p < n; k *= 2, m = p, p = 0){
            for(int i = n - k + 1; i <= n; i++) y[++p] = i;
            for(int i = 1; i <= n; i++) if(sa[i] > k) y[++p] = sa[i] - k;
            for(int i = 0; i <= m; i++) buc[i] = 0;
            for(int i = 1; i <= n; i++) buc[x[y[i]]]++;
            for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
            for(int i = n; i; i--) sa[buc[x[y[i]]]--] = y[i];
            swap(x, y), x[sa[1]] = 1, p = 1;
            for(int i = 2; i <= n; i++)
                x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
        }
        for(int i = 1; i <= n; i++) rnk[sa[i]] = i;
        for(int i = 1, k = 0; i <= n; i++){
            if(rnk[i] == 1) continue;
            int j = sa[rnk[i] - 1];
            if(k) k--;
            while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++;
            height[rnk[i]] = k;
        }
    }
    
    int main(){
    
        scanf("%s", s + 1);
        n = strlen(s + 1);
        suffix_sort();
        memset(data, INF, sizeof(data));
        memset(lazy, INF, sizeof(lazy));
        for(int i = 1; i <= n; i++){
            int len = max(height[rnk[i]], height[rnk[i] + 1]);
            if(i + len <= n) modify(0, 1, 1, n, i, i + len, len + 1);
            if(i + len < n) modify(1, 1, 1, n, i + len + 1, n, 1 - i);
        }
        pushdown_all(1, 1, n);
        for(int i = 1; i <= n; i++)
            write(min(data[0][pos[i]], i + data[1][pos[i]])), enter;
    
        return 0;
    }
    
  • 相关阅读:
    python-----贴图 和 报错:OSError: image file is truncated (8 bytes not processed)的处理
    springboot集成RabbitMQ
    MySQL数据库设计规范
    腾讯云COS对象存储
    腾讯云OCR图片文字识别
    java基础之 java注释
    centos7下自动备份mysql数据库
    nginx配置ssl证书
    java基础之 控制语句
    js -- 操作sqlite数据库
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/BZOJ2865.html
Copyright © 2011-2022 走看看