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

Posted iat14

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n");
205             else
206                 printf("%d\n",kt.ask(1,len,k,kt.root[tl - 1],kt.root[tr]));
207         
208     
209     return 0;
210 

 

以上是关于hdu 6704 K-th occurrence 二分 ST表 后缀数组 主席树的主要内容,如果未能解决你的问题,请参考以下文章

HDU - 6704 K-th occurrence (后缀数组+主席树/后缀自动机+线段树合并+倍增)

hdu6704 2019CCPC网络选拔赛1003 K-th occurrence 后缀数组

K-th occurrence(后缀树组+划分树+ST表+RMQ+二分)

K-th occurrence

2019CCPC网络预选赛 1003 K-th occurrence 后缀自动机 + 二分 + 主席树

2019 CCPC 网络赛第三题 K-th occurrence 后缀数组+划分树+ST表+二分