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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM