• hdu 6704 K-th occurrence 二分 ST表 后缀数组 主席树


    我们考虑,一个子串必定是某个后缀的前缀。

    排序相邻的后缀他们的前缀一定最相似。

    所以全部的一种子串必定是一些排序相邻的后缀的公共前缀。

    从l开始的子串,则从rank[l]开始看,两侧height保证大于子串长度,能延伸多长,则证明有多少个这种子串。

    我们用ST表维护出height的最小值,然后通过最小值二分即可,边界有些棘手。

    然后我们就得到了一个height不小于子串长度的连续区间,这个区间是以原后缀的字典序排序的。

    而同时,sa数组下标为排序,值为原串位置。

    所以我们对这个区间在sa数组上做主席树,求第k大,即为第k个子串出现的位置。

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <cstring>
      4 #include <cmath>
      5 using namespace std;
      6 const int MAXN = 101000;
      7 char str[MAXN];
      8 int len,q,T,m,uni[30];
      9 struct ktree
     10 {
     11     int n,cnt;
     12     int root[MAXN];
     13     int ls[MAXN * 40],rs[MAXN * 40],s[MAXN * 40];
     14 //插入一个新的版本,参数分别为左右区间,最近的历史版本,现在的版本,插入的值
     15 //k值加一个引用可以完美的处理新子节点的序号分配问题。
     16 //s数组记录了对应序号子树的元素个数
     17     void insert(int l,int r,int pre,int &k,int v)
     18     {
     19         k = ++cnt;
     20         s[k] = s[pre] + 1;
     21         if (l == r)
     22             return;
     23         int mid = (l + r) >> 1;
     24         //由于我们k值传了引用参,所以这里可以直接将左右节点全部赋上值。
     25         ls[k] = ls[pre];
     26         rs[k] = rs[pre];
     27         //根据情况来进行左右递归。
     28         if (v <= mid)
     29             insert(l,mid,ls[pre],ls[k],v);
     30         else
     31             insert(mid + 1,r,rs[pre],rs[k],v);
     32     }
     33 //查询x,y两个历史版本的权值线段树相减的得到新的线段树中的第k大
     34 //这里我们考虑一下,如果我们求区间[x,y]的第k大。那么显然第x-1个版本相当于[1,x-1]的权值线段树,那么我们用第y个版本的线段树-第x-1个版本的线段树,得到就相当于是[x,y]区间得到的权值线段树,然后我们可以在这棵线段树上进行开心的查询。
     35     int ask(int l,int r,int k,int x,int y)
     36     {
     37         if (l == r)
     38             return l;
     39         int mid = (l + r) >> 1;
     40         if (s[ls[y]] - s[ls[x]] >= k)
     41             return ask(l,mid,k,ls[x],ls[y]);
     42         return ask(mid + 1,r,k - (s[ls[y]] - s[ls[x]]),rs[x],rs[y]);
     43     }
     44     void build(int _n,int *vec)
     45     {
     46         n = _n;
     47         for (int i = 1; i <= n; i++)
     48             insert(1,n,root[i - 1],root[i],vec[i]);
     49     }
     50     void clear()
     51     {
     52         for (int i = 1; i <= cnt; i++)
     53             s[i] = ls[i] = rs[i] = 0;
     54         for (int i = 0; i <= n; i++)
     55             root[i] = 0;
     56         n = 0;
     57         cnt = 0;
     58     }
     59 } kt;
     60 struct suffixvec
     61 {
     62     int c[MAXN],sa[MAXN],rnk[MAXN],height[MAXN],tp[MAXN];
     63     int m,len;
     64     char str[MAXN];
     65     void build(int _len,char *s)
     66     {
     67         len = _len;
     68         strcpy(str + 1,s + 1);//因为要从1开始 
     69     }
     70     void clear()
     71     {
     72         for (int i = 1; i <= len; i++)
     73             sa[i] = rnk[i] = height[i] = 0;
     74     }
     75     void qsort()
     76     {
     77         for (int i = 0; i <= m; i++)
     78             c[i] = 0;
     79         for (int i = 1; i <= len; i++)
     80             c[rnk[i]]++;
     81         for (int i = 1; i <= m; i++)
     82             c[i] += c[i - 1];
     83         for (int i = len; i >= 1; i--)
     84             sa[c[rnk[tp[i]]]--] = tp[i];
     85     }
     86     void get_sa()
     87     {
     88         m = 200;
     89         for (int i = 1; i <= len; i++)
     90         {
     91             rnk[i] = str[i];
     92             tp[i] = i;
     93         }
     94         qsort();
     95         for (int k = 1,p = 0; p < len; m = p,k <<= 1)
     96         {
     97             p = 0;
     98             for (int i = 1; i <= k; i++)
     99                 tp[++p] = len - k + i;
    100             for (int i = 1; i <= len; i++)
    101                 if (sa[i] > k)
    102                     tp[++p] = sa[i] - k;
    103             qsort();
    104             swap(tp,rnk);
    105             rnk[sa[1]] = p = 1;
    106             for (int i = 2; i <= len; i++)
    107                 rnk[sa[i]] = (tp[sa[i - 1]] == tp[sa[i]] && tp[sa[i - 1] + k] == tp[sa[i] + k]) ? p : ++p;
    108         }
    109     }
    110     int solve(int x,int y)
    111     {
    112         int res = 0;
    113         while (str[x++] == str[y++])
    114             res++;
    115         return res;
    116     }
    117     void get_height()
    118     {
    119         int cur = 0;
    120         for (int i = 1; i <= len; i++)
    121         {
    122             if (cur != 0)
    123                 cur--;
    124             height[rnk[i]] = cur = cur + solve(i + cur,sa[rnk[i] + 1] + cur);
    125         }
    126     }
    127 } sf;
    128 struct stable
    129 {
    130     int p[MAXN][30];
    131     int len;
    132     void init(int _len,int *vec)
    133     {
    134         len = _len;
    135         int tp = log2(len);
    136         for (int i = 1; i <= len; i++)
    137             p[i][0] = vec[i];
    138         for (int i = 1; i <= tp; i++)
    139             for (int j = 1; j + uni[i] - 1 <= len; j++)
    140                 p[j][i] = min(p[j][i - 1],p[j + uni[i - 1]][i - 1]);
    141     }
    142     int querymin(int l,int r)
    143     {
    144         int tp = log2(r - l + 1);
    145         return min(p[l][tp],p[r - uni[tp] + 1][tp]);
    146     }
    147 } st;
    148 int tdl(int x,int lt)
    149 {
    150     int l = 1,r = x;
    151     while (l < r)
    152     {
    153         int mid = l + r >> 1;
    154         if (st.querymin(mid,x) >= lt)
    155             r = mid;
    156         else
    157             l = mid + 1;
    158     }
    159     return l;
    160 }
    161 int tdr(int x,int lt)
    162 {
    163     int l = x,r = len;
    164     while (l < r)
    165     {
    166         int mid = l + r + 1 >> 1;
    167         if (st.querymin(x,mid) >= lt)
    168             l = mid;
    169         else
    170             r = mid - 1;
    171     }
    172     return l;
    173 }
    174 
    175 int main()
    176 {
    177     uni[0] = 1;
    178     for (int i = 1; i <= 25; i++)
    179         uni[i] = uni[i - 1] << 1;
    180     for(scanf("%d",&T); T != 0; T--)
    181     {
    182         scanf("%d%d",&len,&q);
    183         scanf("%s",str + 1);
    184         sf.clear();
    185         sf.build(len,str);
    186         sf.get_sa();
    187         sf.get_height();
    188         st.init(sf.len,sf.height);
    189         kt.clear();
    190         kt.build(len,sf.sa);
    191         int l,r,k,tl,tr;
    192         for (int i = 1; i <= q; i++)
    193         {
    194             scanf("%d%d%d",&l,&r,&k);
    195             if (sf.height[sf.rnk[l] - 1] < r - l + 1)
    196                 tl = sf.rnk[l];
    197             else
    198                 tl = tdl(sf.rnk[l] - 1,r - l + 1);
    199             if (sf.height[sf.rnk[l]] < r - l + 1)
    200                 tr = sf.rnk[l];
    201             else
    202                 tr = tdr(sf.rnk[l],r - l + 1) + 1;
    203             if (k > kt.s[kt.root[tr]] - kt.s[kt.root[tl - 1]])
    204                 printf("-1
    ");
    205             else
    206                 printf("%d
    ",kt.ask(1,len,k,kt.root[tl - 1],kt.root[tr]));
    207         }
    208     }
    209     return 0;
    210 }
    心之所动 且就随缘去吧
  • 相关阅读:
    “字节跳动-文远知行杯”广东工业大学第十四届程序设计竞赛
    Codeforces Beta Round 77 (Div. 2 Only)
    Codeforces Round 263(Div. 2)
    Codeforces Round 262 (Div. 2)
    《Introduction to Algorithm》-chaper30-多项式与快速傅里叶变换
    算法专题-STL篇
    算法专题-暴力枚举篇
    初等数论及其应用——中国剩余定理
    初等数论及其应用——费马小定理
    《A First Course in Probability》-chape4-离散型随机变量-几种典型分布列
  • 原文地址:https://www.cnblogs.com/iat14/p/11402468.html
Copyright © 2020-2023  润新知