[whu1564]后缀树组

http://acm.whu.edu.cn/land/problem/detail?problem_id=1564

思路:先把串复制一遍,在末尾补个标记,后缀树组跑一下,扫一遍就ok了(过滤后缀在后半部分的)。

  1 #pragma comment(linker, "/STACK:10240000,10240000")
  2
  3 #include <iostream>
  4 #include <cstdio>
  5 #include <algorithm>
  6 #include <cstdlib>
  7 #include <cstring>
  8 #include <map>
  9 #include <queue>
 10 #include <deque>
 11 #include <cmath>
 12 #include <vector>
 13 #include <ctime>
 14 #include <cctype>
 15 #include <set>
 16 #include <bitset>
 17 #include <functional>
 18 #include <numeric>
 19 #include <stdexcept>
 20 #include <utility>
 21
 22 using namespace std;
 23
 24 #define mem0(a) memset(a, 0, sizeof(a))
 25 #define mem_1(a) memset(a, -1, sizeof(a))
 26 #define lson l, m, rt << 1
 27 #define rson m + 1, r, rt << 1 | 1
 28 #define define_m int m = (l + r) >> 1
 29 #define rep_up0(a, b) for (int a = 0; a < (b); a++)
 30 #define rep_up1(a, b) for (int a = 1; a <= (b); a++)
 31 #define rep_down0(a, b) for (int a = b - 1; a >= 0; a--)
 32 #define rep_down1(a, b) for (int a = b; a > 0; a--)
 33 #define all(a) (a).begin(), (a).end()
 34 #define lowbit(x) ((x) & (-(x)))
 35 #define constructInt4(name, a, b, c, d) name(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), d(d) {}
 36 #define constructInt3(name, a, b, c) name(int a = 0, int b = 0, int c = 0): a(a), b(b), c(c) {}
 37 #define constructInt2(name, a, b) name(int a = 0, int b = 0): a(a), b(b) {}
 38 #define pchr(a) putchar(a)
 39 #define pstr(a) printf("%s", a)
 40 #define sstr(a) scanf("%s", a)
 41 #define sint(a) scanf("%d", &a)
 42 #define sint2(a, b) scanf("%d%d", &a, &b)
 43 #define sint3(a, b, c) scanf("%d%d%d", &a, &b, &c)
 44 #define pint(a) printf("%d\n", a)
 45 #define test_print1(a) cout << "var1 = " << a << endl
 46 #define test_print2(a, b) cout << "var1 = " << a << ", var2 = " << b << endl
 47 #define test_print3(a, b, c) cout << "var1 = " << a << ", var2 = " << b << ", var3 = " << c << endl
 48
 49 typedef double db;
 50 typedef long long LL;
 51 typedef pair<int, int> pii;
 52 typedef multiset<int> msi;
 53 typedef set<int> si;
 54 typedef vector<int> vi;
 55 typedef map<int, int> mii;
 56
 57 const int dx[8] = {0, 0, -1, 1, 1, 1, -1, -1};
 58 const int dy[8] = {-1, 1, 0, 0, 1, -1, 1, -1 };
 59 const int maxn = 1e6 + 7;
 60 const int md = 1e9 + 7;
 61 const int inf = 1e9 + 7;
 62 const LL inf_L = 1e18 + 7;
 63 const double pi = acos(-1.0);
 64 const double eps = 1e-6;
 65
 66 template<class T>T gcd(T a, T b){return b==0?a:gcd(b,a%b);}
 67 template<class T>bool max_update(T &a,const T &b){if(b>a){a = b; return true;}return false;}
 68 template<class T>bool min_update(T &a,const T &b){if(b<a){a = b; return true;}return false;}
 69 template<class T>T condition(bool f, T a, T b){return f?a:b;}
 70 template<class T>void copy_arr(T a[], T b[], int n){rep_up0(i,n)a[i]=b[i];}
 71 int make_id(int x, int y, int n) { return x * n + y; }
 72
 73
 74 /// 构造后缀数组的之前,需要在原串末尾加个空字符(比其它字符都小即可),
 75 ///把这个空字符看成原串的一部分(这样在比较的时候到这个位置一定可以分个大小),
 76 ///所以n应该为原序列长度+1,后缀n-1是"空串",sa[0]总是n-1。
 77 struct SuffixArray {
 78     int n;
 79     int arr[6][maxn];
 80     int *sa, *x, *y, *c, *rnk, *height;
 81     SuffixArray() { sa = arr[0]; x = arr[1]; y = arr[2]; c = arr[3]; rnk = arr[4]; height = arr[5]; }
 82     void resize(int nn) {  n = nn; mem0(arr[0]); }
 83     void build_sa(int s[], int m) { // m is biger than the max value of char
 84         rep_up0(i, m) c[i] = 0;
 85         rep_up0(i, n) c[x[i] = s[i]]++;
 86         rep_up1(i, m - 1) c[i] += c[i - 1];
 87         rep_down0(i, n) sa[--c[x[i]]] = i;
 88         for (int k = 1; k <= n; k <<= 1) {
 89             int p = 0;
 90             for (int i = n - k; i < n; i++) y[p++] = i;
 91             rep_up0(i, n) if (sa[i] >= k) y[p++] = sa[i] - k;
 92             rep_up0(i, m) c[i] = 0;
 93             rep_up0(i, n) c[x[y[i]]]++;
 94             rep_up0(i, m) c[i] += c[i - 1];
 95             rep_down0(i, n) sa[--c[x[y[i]]]] = y[i];
 96             swap(x, y);
 97             p = 1; x[sa[0]] = 0;
 98             for (int i = 1; i < n; i++) {
 99                 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k]? p - 1 : p++;
100             }
101             if (p >= n) break;
102             m = p;
103         }
104     }
105     void build_height(int s[]) {
106         int k = 0;
107         rep_up0(i, n) rnk[sa[i]] = i;
108         rep_up0(i, n) {
109             if (k) k--;
110             int j = sa[rnk[i] - 1];
111             while (s[i + k] == s[j + k]) k++;
112             height[rnk[i]] = k;
113         }
114     }
115 };
116
117 SuffixArray sa;
118 char s[maxn];
119 int ss[maxn];
120
121 int main() {
122     //freopen("in.txt", "r", stdin);
123     int n, k;
124     while (cin >> n >> k) {
125         scanf("%s", s);
126         rep_up0(i, n) ss[i + n] = ss[i] = s[i];
127         ss[2 * n] = 0;
128         int len = n * 2 + 1;
129         sa.resize(len);
130         sa.build_sa(ss, 128);
131         int cnt = 0;
132         for (int i = 1; i < len; i++) {
133             if (sa.sa[i] < n) {
134                 cnt++;
135                 if (cnt == k) {
136                     int x = sa.sa[i];
137                     if (x == 0) x = n;
138                     cout << x << endl;
139                     break;
140                 }
141             }
142         }
143     }
144     return 0;
145 }

时间: 2024-10-14 10:09:46

[whu1564]后缀树组的相关文章

ural1297(后缀树组+rmq)

Palindrome 题意: 求给定字符串的最长回文子串. 分析: 首先想到的是求str与反序的str的最大公共子串,考虑abcdba这种情况,所以对于求出的公共子串判断一下是否是回文串即可.还有一种做法是枚举每一个字符为回文串的中间点,求出这个字符的后缀与前缀的最长公共子串就是回文串.对于前缀可以认为是反序str中对应字符的后缀,根据后缀树组中height数组的性质,suffix(i)和suffix(j)的最长公共前缀为height[rank[i]+1],height[rank[i]+2]--

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

2019CCPC网络选拔赛1003 HDU6704 题目大意: T个测试样例.一个长度为N的字符串S,之后Q个[l,r,k],表示一个子串S[l,r],求出第k个该子串的下标.起始坐标为1.不存在输出-1. 数据范围:1≤T≤20,  1≤N≤105,  1≤Q≤105,  1≤l≤r≤N,  1≤k≤N,  |S|=N; 赛后补题.参考题解说后缀树组+划分树+ST表+二分. 比赛的时候只会后缀树组不会划分树,赛后仔细想,觉得后缀数组可以,然而并不,会TLE. 补提的时候先是采用后缀树组+划分树

后缀树组(SA)初探

还没有什么任意两个后缀的LCP这些玩意儿. 启蒙题:输入一个串S,求最长的串T使得T在S中出现过不止一次.输出T的长度. 1 #include <algorithm> 2 #include <stdio.h> 3 #include <string.h> 4 #define N 100 5 char s[N+1]; 6 int n, sa[N], rank[N], height[N]; 7 namespace SABuilder { 8 int cnt[N], t1[N&

POJ3581---Sequence 后缀树组

题意:n个数字组成的序列,第一个数字最大,,把序列分成3部分,每个部分分别翻转,输出翻转后字典序最小的序列.. 后缀数组变一下,,先求出 第一个分割的位置,,然后再求一次后缀数组,,求出第二个位置..输出就好了. 此题要采用单组输入... 1 #include <set> 2 #include <map> 3 #include <cmath> 4 #include <ctime> 5 #include <queue> 6 #include <

HDU4436---str2int 后缀树组(12年天津区域赛)

str2int Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1568    Accepted Submission(s): 540 Problem Description In this problem, you are given several strings that contain only digits from '0'

[转载]字典树(trie树)、后缀树

(1)字典树(Trie树) Trie是个简单但实用的数据结构,通常用于实现字典查询.我们做即时响应用户输入的AJAX搜索框时,就是Trie开始.本质上,Trie是一颗存储多个字符串的树.相邻节点间的边代表一个字符,这样树的每条分支代表一则子串,而树的叶节点则代表完整的字符串.和普通树不同的地方是,相同的字符串前缀共享同一条分支.还是例子最清楚.给出一组单词,inn, int, at, age, adv, ant, 我们可以得到下面的Trie: 可以看出: 每条边对应一个字母. 每个节点对应一项前

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类

后缀树

在<字符串匹配算法>一文中,我们熟悉了字符串匹配问题的形式定义: 文本(Text)是一个长度为 n 的数组 T[1..n]: 模式(Pattern)是一个长度为 m 且 m≤n 的数组 P[1..m]: T 和 P 中的元素都属于有限的字母表 Σ 表: 如果 0≤s≤n-m,并且 T[s+1..s+m] = P[1..m],即对 1≤j≤m,有 T[s+j] = P[j],则说模式 P 在文本 T 中出现且位移为 s,且称 s 是一个有效位移(Valid Shift). 比如上图中,目标是找出

树状树组(Binary Indexed Tree (BIT))的C++部分实现

一.树状数组的用处 树状树组是将一个线性数组保存为“树状”,当修改某点的值.求某个区间的和的时候能够有效的减少时间复杂度.当数组长度为N,实时对数组进行M次修改或求和,最坏的情况下复杂度是O(M*N). 二.树状数组的建立 假设输入数组为 vector<int> nums 将其转化为树状数组的本质在于将数组的原先顺序打乱后,经过特殊的求和方法,组合成新的数组,代码如下.关键点在于k+=k&-k,这是一个利用二进制码的特点完成树状数组下标的选取. 1 size = nums.size()