2019 CCPC network third season title K-th occurrence suffix array + partitioning tree + table + ST-half

Question is intended: to give you a string of length n, the number three is given every inquiry: L, R, K, L represents a sub-string of the original R to the original string in the letter string of the first occurrence of the K-th position

Problem-solving ideas: a large number of substrings operation, difficult to think suffix array ( suffix tree / suffix automaton not, so did not expect ), noted substring s [L ..... R] is necessarily a suffix prefix, so all of the prefix is the substring suffix ranking (ie, the value rank of the array) must be continuous, that is to say in the suffix array (sa array), the index is continuous, it is seeking a large range of K (because the value represented sa array is position in the string) (where interval K Great I pray with the partition tree), as the beginning and end of this period interval, can find use binary, because rank [L] must be a value interval in the request, then it may be Rank [L] as the center, left and right, respectively, half extended section outwardly bipartite check function (decision established conditions) can be determined suffix of the current position and the L suffix beginning - the LCP (longest common prefix), determines whether or not less than (R - L + 1) to, natural language comparative weakness, see bar codes directly =. =

#include <bits / STDC ++ H.>
 the using  namespace STD;
 const  int MAXN = 100010 ;
 int n-; 

/ * ************************************************************ Suffix Array ** ************************************************************ * / 
// the X-[i] represents the beginning of the i-character suffix in all suffix ranking sa [i ] represents the beginning of the ranking is the suffix i of the position of the character 
int SA [MAXN], X [MAXN], C [MAXN], Y [MAXN], height [MAXN]; 
; 
char S [MAXN];
 void SA () // O (nlogn) multiplying seeking suffix array 
{
     int m = 128 ;
     for ( int I = 0 ; I <= m; I ++ ) 
        C [I] =0;
    for (int i = 1; i <= n; i++)
        c[x[i] = s[i]]++;
    for (int i = 1; i <= m; i++)
        c[i] += c[i - 1];
    for (int i = n; i >= 1; i--)
        sa[c[x[i]]--] = i;

    for (int k = 1; k <= n; k <<= 1)
    {
        int p = 0;
        for (int i = 0; i <= m; i++)
            y[i] = 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++)
            c[i] = 0;
        for (int i = 1; i <= n; i++)
            c[x[y[i]]]++;
        for (int i = 1; i <= m; i++)
            c[i] += c[i - 1];
        for (int i = n; i >= 1; i--)
            sa[c[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;
        if (p >= n)
            break;
        m = p;
    }
}
void get_height() //求height数组
{
    int k = 0;
    //for (int i=1; i<=n; ++i) rk[sa[i]]=i; x数组即为rank数组
    for (int i = 1; i <= n; ++i)
    {
        if (x[i] == . 1 )
             Continue ;
         IF (K)
             - K;
         int J = SA [X [I] - . 1 ];
         the while (J + K <= n-K + && I <= n-&& S [K + I] == S [J + K])
             ++ K; 
        height [X [I]] = K; 
    } 
} 
/ * ************************************************************ *************************************** * / 

/ * ******* ****************** trees began to divide ************************************************************ * / 
int tree [ 30 ] [MAXN];    // denotes each value of each position 
int the sorted [MAXN];     // sorted number 
int toleft [ 30 ] [MAXN]; // toleft [P] [i] denotes the i-layer number i from 1 to the number of points left 

void Build ( int L, int R & lt, int DEP ) 
{ 
    IF (L == R & lt)
         return ;
     int mID = (L + R & lt) >> . 1 ;
     int Same mID = - L + . 1 ;       // represents an intermediate value equal to the left and is divided into a number of first initialized to the left after the number of minus 
    for ( int I = L; I <= R & lt; I ++) // is not L One 
    {
         IF (Tree [DEP] [I] < the sorted [MID])
            Same- ; 
    } 
    int LPOS = L;
     int RPOS = MID + . 1 ; // first two child nodes of this node 
    for ( int I = L; I <= R & lt; I ++ ) 
    { 
        IF (Tree [DEP] [I ] <the sorted [mID]) // less than the number of intermediate, divided into left 
            Tree [DEP + . 1 ] [LPOS ++] = Tree [DEP] [I];
         the else  IF (Tree [DEP] [I] == the sorted [ MID] && Same> 0 ) 
        { 
            Tree [DEP + . 1 ] [LPOS ++] = Tree [DEP] [I]; 
            Same - ;
        } 
        The else  // than the intermediate value Oita into the right 
            Tree [DEP + . 1 ] [RPOS ++] = Tree [DEP] [I]; 
        toleft [DEP] [I] = toleft [DEP] [L - . 1 ] + LPOS - L; // number from 1 to put the left I 
    } 
    Build (L, MID, DEP + 1 ); 
    Build (MID + 1 , R & lt, DEP + 1 ); 
} 

// query a large number of the k-th interval, [L, R] is a large interval, [l, r] is the inter-cell to query 
int query ( int L, int R & lt, int L, int R & lt, int DEP, int  K)
{ 
    IF (L == R & lt)
         return Tree [DEP] [L];
     int MID = (L + R & lt) >> . 1 ;
     int CNT = toleft [DEP] [R & lt] - toleft [DEP] [L - . 1 ]; / / [L, R & lt] on the left in the number of 
    IF (CNT> = K) 
    { 
        // L + is on the left side of the front section to the number of query 
        int NewL = L + toleft [DEP] [L - . 1 ] - toleft [DEP] [L - . 1 ];
         // left point plus the number of query section will be placed on the left 
        int newr NewL = CNT + - . 1 ;
         return query (L, MID, NewL, newr, DEP + . 1 , K); 
    } 
    the else 
    {
        int newr = r + toleft[dep][R] - toleft[dep][r];
        int newl = newr - (r - l - cnt);
        return query(mid + 1, R, newl, newr, dep + 1, k - cnt);
    }
}
/***************************划分树结束***********************************/

inline int read()
{
    int sgn = 1;
    int cnt = 0;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            sgn = -sgn;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9')
    {
        cnt = cnt * 10 + (ch - '0');
        ch = getchar();
    }
    return sgn * cnt;
}

/****************************   S  T  表   ****************************/
int g[maxn][20]; //区间最小
void ST_prewoek()
{
    for (int i = 1; i <= n; i++)
    {
        g[i][0] = height[i];
    }
    for (int i = 1, imax = log2(n); i <= imax; i++)
    {
        for (int j = 1; j + (1 << i) - 1 <= n; j++) //Note that the right end point j j + (1 << i) -1 , -1 is due to their containing j 
        { 
            G [j] [I] = min (G [j] [I - . 1 ], G [j + ( . 1 << I - . 1 )] [I - . 1 ]); 
        } 
    } 
} 

int ST_query ( int L, int R & lt) // find [l, the minimum value r] in 
{
     int K = Iog2 (R & lt - L + . 1 );
     return min (G [L] [K], G [R & lt - ( . 1 << K) + . 1 ] [K]); 
} 
/ * ********************************************************* ****************************************** * / 

BOOL the Check ( int l, int r, int len) //二分判断函数
{
    if (l == r)
        return true;
    l = x[l];
    r = x[r];
    if (l > r)
        swap(l, r);
    if (ST_query(l + 1, r) > len)
        return true;
    return false;
}

int main()
{
    int t, Q;
    scanf("%d", &t);
    while (t--)
    {
        memset(tree, 0, sizeof(tree));
        scanf("%d%d", &n, &Q);
        scanf("%s", s + 1);
        SA();
        get_height();
        for (int i = 1; i <= n; i++)
        {
            tree[0][i] = sorted[i] = sa[i];
        }
        sort(sorted + 1, sorted + n + 1);
        build(1, n, 0);
        ST_prewoek();
        int l, r, k;
        while (Q--)
        {
            l = read();
            r = read();
            k = read();
            int rk = x[l], len = r - l;
            int tl = 1, tr = rk;
            int nl = rk, nr = rk;
            while (tl <= tr)
            {
                int mid = (tl + tr) / 2;
                if (check(sa[mid], l, len))
                {
                    nl = mid;
                    tr = mid - 1;
                }
                else
                {
                    tl = mid + 1;
                }
            }
            tl = rk;
            tr = n;
            while (tl <= tr)
            {
                int mid = (tl + tr) / 2;
                if (check(sa[mid], l, len))
                {
                    nr = mid;
                    tl = mid + 1;
                }
                else
                {
                    tr = mid - 1;
                }
            }
            if (nr - nl + 1 < k)
            {
                puts("-1");
            }
            else
            {
                printf("%d\n", query(1, n, nl, nr, 0, k));
            }
        }
    }
    return 0;
}

 

Guess you like

Origin www.cnblogs.com/Zeronera/p/11403335.html