zoukankan      html  css  js  c++  java
  • [TJOI2016 & HEOI2016] 字符串

    [题目链接]

            https://www.lydsy.com/JudgeOnline/problem.php?id=4556

    [算法]

            不难发现 , 对于每个询问
            ans = max{ min{b - i + 1 , lcp(i , c) } (a <= i <= b)

            不妨二分答案mid , 那么问题就转化为求 max{ lcp(i  , c) } (a <= i <= b - mid + 1)

             而我们知道 , 所有lcp(i , j) <= k的i是连续的一段区间

             可以再次通过二分求出这个区间

             问题又转化为判断[a , b - mid + 1]中是否有rank值在区间[L , R]中的数

             构建出后缀数组 , 主席树维护rank值即可

             时间复杂度 : O(NlogN ^ 2)

    [代码]

            

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e5 + 10;
    const int MAXLOG = 17;
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    
    #define rint register int
    
    int n , m;
    int rk[N] , rt[N] , sa[N] , cnt[N] , height[N] , lg[N];
    int val[N][MAXLOG];
    char s[N];
    
    struct Presitent_Segment_Tree
    {
            int sz;
            int lc[N * 40] , rc[N * 40] , cnt[N * 40];
            Presitent_Segment_Tree()
            {
                    sz = 0;
            }
            inline void build(int &now , int l , int r)
            {
                    now = ++sz;
                    if (l == r) return;
                     int mid = (l + r) >> 1;
                     build(lc[now] , l , mid);
                     build(rc[now] , mid + 1 , r);
            }
            inline void modify(int &now , int old , int l , int r , int x , int value)
            {
                    now = ++sz;
                    lc[now] = lc[old] , rc[now] = rc[old];
                    cnt[now] = cnt[old] + value;
                    if (l == r) return;
                    int mid = (l + r) >> 1;
                    if (mid >= x) modify(lc[now] , lc[old] , l , mid , x , value);
                    else modify(rc[now] , rc[old] , mid + 1 , r , x , value);
            }
            inline bool query(int rt1 , int rt2 , int l , int r , int ql , int qr)
            {
                    if (ql > qr || cnt[rt1] - cnt[rt2] == 0) 
                            return false; 
                    if (l == ql && r == qr)
                            return (cnt[rt1] - cnt[rt2] > 0);
                    int mid = (l + r) >> 1;
                    if (mid >= qr) return query(lc[rt1] , lc[rt2] , l , mid , ql , qr);
                    else if (mid + 1 <= ql) return query(rc[rt1] , rc[rt2] , mid + 1 , r , ql , qr);
                    else return query(lc[rt1] , lc[rt2] , l , mid , ql , mid) | query(rc[rt1] , rc[rt2] , mid + 1 , r , mid + 1 , qr);
            }
    } PST;
    template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
    template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
    template <typename T> inline void read(T &x)
    {
        T f = 1; x = 0;
        char c = getchar();
        for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
        for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
        x *= f;
    }
    inline void build_sa()
    {
            static int x[N] , y[N];
        memset(cnt , 0 , sizeof(cnt));
        for (rint i = 1; i <= n; i++) ++cnt[(int)s[i]];
        for (rint i = 1; i <= 256; i++) cnt[i] += cnt[i - 1];
        for (rint i = n; i >= 1; i--) sa[cnt[(int)s[i]]--] = i;
        rk[sa[1]] = 1;
        for (rint i = 2; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]);
        for (rint k = 1; rk[sa[n]] != n; k <<= 1)
        {
            for (rint i = 1; i <= n; i++)
                x[i] = rk[i] , y[i] = (i + k <= n) ? rk[i + k] : 0;
            memset(cnt , 0 , sizeof(cnt));
            for (rint i = 1; i <= n; i++) ++cnt[y[i]];
            for (rint i = 1; i <= n; i++) cnt[i] += cnt[i - 1];
            for (rint i = n; i >= 1; i--) rk[cnt[y[i]]--] = i;
            memset(cnt , 0 , sizeof(cnt));
            for (rint i = 1; i <= n; i++) ++cnt[x[i]];
            for (rint i = 1; i <= n; i++) cnt[i] += cnt[i - 1];
            for (rint i = n; i >= 1; i--) sa[cnt[x[rk[i]]]--] = rk[i];
            rk[sa[1]] = 1;
            for (rint i = 1; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (x[sa[i]] != x[sa[i - 1]] || y[sa[i]] != y[sa[i - 1]]); 
        }
    }
    inline void get_height()
    {
        int k = 0;
        for (rint i = 1; i <= n; i++)
        {
            if (k) --k;
            int j = sa[rk[i] - 1];
            while (s[i + k] == s[j + k]) ++k;
            height[rk[i]] = k;
        }    
    }
    inline void rmq_init()
    {
            for (rint i = 1; i <= n; i++)
                    val[i][0] = height[i];
            for (rint j = 1; (1 << j) <= n; j++)
            {
                    for (rint i = 1; i + (1 << j) - 1 <= n; i++)
                    {
                            val[i][j] = min(val[i][j - 1] , val[i + (1 << (j - 1))][j - 1]);
                    }
            }
    }
    inline int query(int x , int y)
    {
            if (x > y) return 0;
            int k = lg[y - x + 1];
            return min(val[x][k] , val[y - (1 << k) + 1][k]);
    }
    
    int main()
    {
            
            scanf("%d%d" , &n , &m);
            scanf("%s" , s + 1);
            build_sa();
            get_height();
            rmq_init();
            PST.build(rt[0] , 1 , n);
            for (rint i = 1; i <= n; i++) PST.modify(rt[i] , rt[i - 1] , 1 , n , rk[i] , 1);
            for (rint i = 1; i <= n; i++) lg[i] = (double)(log(i) / log(2.0));
            while (m--)
            {
                    int a , b , c , d;
                    read(a); read(b); read(c); read(d);
                    int l = 1 , r = min(d - c + 1 , b - a + 1) , ans = 0;
                    while (l <= r)
                    {
                            int mid = (l + r) >> 1;
                            int ll = 1 , rr = rk[c] - 1 , L = rk[c] , R = rk[c];
                            while (ll <= rr)
                            {
                                    int md = (ll + rr) >> 1;
                                    if (query(md + 1 , rk[c]) >= mid)
                                    {
                                            L = md;
                                            rr = md - 1;
                                    } else ll = md + 1;
                            }
                            ll = rk[c] + 1 , rr = n , R = rk[c];
                            while (ll <= rr)
                            {
                                    int md = (ll + rr) >> 1;
                                    if (query(rk[c] + 1 , md) >= mid)
                                    {
                                            R = md;
                                            ll = md + 1;
                                    } else rr = md - 1;
                            }
                            if (PST.query(rt[b - mid + 1] , rt[a - 1] , 1 , n , L , R)) 
                            {
                                    l = mid + 1;
                                    ans = mid;
                            } else r = mid - 1;
                    }
                    printf("%d
    " , ans);
            }
            
            return 0;
        
    }
  • 相关阅读:
    ....
    CodeForces 375A(同余)
    POJ 2377 Bad Cowtractors (最小生成树)
    POJ 1258 AgriNet (最小生成树)
    HDU 1016 Prime Ring Problem(全排列)
    HDU 4460 Friend Chains(bfs)
    POJ 2236 Wireless Network(并查集)
    POJ 2100 Graveyard Design(尺取)
    POJ 2110 Mountain Walking(二分/bfs)
    CodeForces 1059B Forgery(模拟)
  • 原文地址:https://www.cnblogs.com/evenbao/p/10459668.html
Copyright © 2011-2022 走看看