HDU 6704 K-th occurrence(主席树 + RMQ + 后缀数组)题解
题意:
给一个串\(S\),\(length\leq 1e5\),\(Q\leq1e5\)个询问,每次询问输出和\(S_lS_{l+1}\dots S_r\)长得一模一样的第\(k\)个子串的开头位置。
思路:
用后缀数组处理一下,那么所有相同子串最后的\(sa\)都会靠在一起,所以找到对应的\(height\)位置,然后向左向右延伸直到\(LCP\)长度不足\(r-l+1\)(\(RMQ\)然后二分左右第一个长度比\(r-l+1\)小的位置),那么就找到了所有和\(S_lS_{l+1}\dots S_r\)长得一模一样的开始位置,然后在主席树上找第\(k\)大。
代码:
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const ull seed = 131;
const ll MOD = 1e9;
using namespace std;
struct node{int lson, rson;int num;
}T[maxn * 40];
int root[maxn], tot;
void init(){tot = 0;memset(T, 0, sizeof(T));
}
void update(int l, int r, int &now, int pre, int pos, int v){T[++tot] = T[pre], now = tot;T[now].num += v;if(l == r) return;int m = (l + r) >> 1;if(pos <= m)update(l, m, T[now].lson, T[pre].lson, pos, v);elseupdate(m + 1, r, T[now].rson, T[pre].rson, pos, v);
}
int queryK(int l, int r, int now, int pre, int k){if(l == r) return l;int m = (l + r) >> 1, Lsum;Lsum = T[T[now].lson].num - T[T[pre].lson].num;if(Lsum >= k)return queryK(l, m, T[now].lson, T[pre].lson, k);elsereturn queryK(m + 1, r, T[now].rson, T[pre].rson, k - Lsum);
}int str[maxn]; //str[n]赋值一个最小值0,其他大于0
int t1[maxn], t2[maxn], c[maxn];
int sa[maxn]; //排名为i的后缀下标
int rk[maxn]; //后缀下标为i的排名
int height[maxn]; //sa[i]与sa[i - 1]的LCP
bool cmp(int *r, int a, int b, int l){return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *str, int n, int m){n++;int i, j, p, *x = t1, *y = t2;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[i] = str[i]]++;for(i = 1; i < m; i++) c[i] += c[i - 1];for(i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;for(j = 1; j <= n; j <<= 1){p = 0;for(i = n - j; i < n; i++) y[p++] = i;for(i = 0; i < n; i++) if(sa[i] >= j) y[p++] = sa[i] - j;for(i = 0; i < m; i++) c[i] = 0;for(i = 0; i < n; i++) c[x[y[i]]]++;for(i = 1; i < m; i++) c[i] += c[i - 1];for(i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];swap(x, y);p = 1; x[sa[0]] = 0;for(i = 1; i < n; i++)x[sa[i]] = cmp(y, sa[i - 1], sa[i], j)? p - 1 : p++;if(p >= n) break;m = p;}int k = 0;n--;for(i = 0; i <= n; i++) rk[sa[i]] = i;for(i = 0; i < n; i++){if(k) k--;j = sa[rk[i] - 1];while(str[i + k] == str[j + k]) k++;height[rk[i]] = k;}
}
int n;
int dp[maxn][20], mm[maxn];
void initRMQ(){mm[0] = -1;for(int i = 1; i <= n; i++){mm[i] = ((i & (i - 1)) == 0)? mm[i - 1] + 1 : mm[i - 1];dp[i][0] = height[i];}for(int j = 1; j <= mm[n]; j++){for(int i = 1; i + (1 << j) - 1 <= n; i++){dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);}}
}
int rmq(int st, int en){int k = mm[en - st + 1];return min(dp[st][k], dp[en - (1 << k) + 1][k]);
}
int getL(int pos, int len){int l = 2, r = pos;while(l <= r){if(l == r){if(height[l] >= len) return l - 1;return l;}int m = (l + r) >> 1;if(rmq(m + 1, r) < len){l = m + 1;}else{r = m;}}
}
int getR(int pos, int len){int l = pos, r = n;while(l <= r){if(l == r){if(height[l] >= len) return l;return l - 1;}int m = (l + r) >> 1;if(rmq(l, m) < len){r = m;}else{l = m + 1;}}
}
int m;
char s[maxn];
int main(){int T;scanf("%d", &T);while(T--){scanf("%d%d", &n, &m);scanf("%s", s);int LEN = 0;for(int i = 0; i < n; i++){str[LEN++] = s[i] - 'a' + 1;}str[LEN] = 0;da(str, LEN, 30);// for(int i = 1; i <= n; i++){
// printf("%2d * ", i);
// for(int j = sa[i]; j < LEN; j++){
// printf("%c", str[j] - 1 + 'a');
// }
// puts("");
// }init();initRMQ();for(int i = 1; i <= n; i++){update(1, n, root[i], root[i - 1], sa[i] + 1, 1);}while(m--){int l, r, k;scanf("%d%d%d", &l, &r, &k);l--, r--;if(n == 1){if(k == 1) printf("1\n");else printf("-1\n");continue;}int len = r - l + 1;if(rk[l] == 1){if(height[2] < len && k == 1) printf("%d\n", l + 1);else if(height[2] < len) printf("-1\n");else{int pos = 2;int pl = getL(pos, len), pr = getR(pos, len);if(pr - pl + 1 < k) printf("-1\n");else printf("%d\n", queryK(1, n, root[pr], root[pl - 1], k));}}else if(rk[l] == n){if(height[n] < len && k == 1) printf("%d\n", l + 1);else if(height[n] < len) printf("-1\n");else{int pos = n;int pl = getL(pos, len), pr = getR(pos, len);if(pr - pl + 1 < k) printf("-1\n");else printf("%d\n", queryK(1, n, root[pr], root[pl - 1], k));}}else{if(max(height[rk[l]], height[rk[l] + 1]) < len && k == 1) printf("%d\n", l + 1);else if(max(height[rk[l]], height[rk[l] + 1]) < len) printf("-1\n");else{int pos = height[rk[l]] > height[rk[l] + 1]? rk[l] : rk[l] + 1;int pl = getL(pos, len), pr = getR(pos, len);if(pr - pl + 1 < k) printf("-1\n");else printf("%d\n", queryK(1, n, root[pr], root[pl - 1], k));}}}}return 0;
}
转载于:https://www.cnblogs.com/KirinSB/p/11424053.html
HDU 6704 K-th occurrence(主席树 + RMQ + 后缀数组)题解相关推荐
- 数据库应用-后缀树及后缀数组(Suffix-BäumeSuffix-Arraz)-2
McCreight-Algorithmus 在O(n)时间内构造后缀树 基本思想 在ST中插入 suffi suff_i时,以下内容可以起到帮助作用: 1.v是ST中从根节点到叶节点i-1的一个内部节 ...
- 后缀树和后缀数组的一些资料收集
后缀树(Suffix tree)是一种数据结构,能快速解决很多关于字符串的问题.后缀树的概念最早由Weiner 于1973年提出,既而由McCreight 在1976年和Ukkonen在1992年和1 ...
- 字符串相关处理kmp,前缀数,后缀树,后缀数组,最长回文串,最长重复字串,最长非重复字串
1. 最长回文串 一般用后缀数组或者后缀树可以解决, 用此方法:http://blog.csdn.net/v_july_v/article/details/6897097 预处理后缀树,使得查询LCA ...
- K-th Closest Distance HDU - 6621(第k小绝对值+主席树+二分)
You have an array: a1, a2, , an and you must answer for some queries. For each query, you are given ...
- hdu 4348 To the moon (主席树)
版权声明:本文为博主原创文章,未经博主允许不得转载. hdu 4348 题意: 一个长度为n的数组,4种操作 : (1)C l r d:区间[l,r]中的数都加1,同时当前的时间戳加1 . (2)Q ...
- HDU - 6621 K-th Closest Distance——主席树+二分
[题目描述] HDU - 6621 K-th Closest Distance [题目分析] 因为看到第kkk大的要求,刚开始的时候一直都在想怎么运用第kkk大来解决问题,但是后来看其他人的博客才发现 ...
- HDU - 6278 Just $h$-index主席树+二分
HDU - 6278 Just hhh-index [题目描述] [题目分析] 题目要求在区间[l,r][l,r][l,r]内大于h的数不少于h个,对于这种最大化问题,我们应该想到二分. 最小情况显然 ...
- HDU 2852 KiKi's K-Number 主席树
题意: 要求维护一个数据结构,支持下面三种操作: \(0 \, e\):插入一个值为\(e\)的元素 \(1 \, e\):删除一个值为\(e\)的元素 \(2 \, a \, k\):查询比\(a\ ...
- HDU - 4348 To the moon(主席树区间更新-标记永久化)
题目链接:点击查看 题目大意:给出一个初始时长度为 n 的序列,有 m 次操作,每种操作分为下列四种类型: C l r d:新建一个继承了前一个版本的数组,并将区间 [ l , r ] 内的数字都加上 ...
- 字符串-后缀树和后缀数组详解
文章目录 后缀树 后缀数组 概念 sa[] rk[] height[] 例题 HDU-1403最长公共子串 洛谷P2408 不同子串个数 HDU-5769Substring 后缀树 建议先了解一下字典 ...
最新文章
- 合肥工业大学—SQL Server数据库实验二:数据库架构的创建与使用
- Service Mesh — Overview
- 这几天在搞UNITY3D,感觉回到了AS2
- 转)SSO单点登录在互联网电商应用中的解决方案(基于CAS的改造)
- Mysql学习总结(8)——MySql基本查询、连接查询、子查询、正则表达查询讲解...
- 【Angular专题】——(1)Angular,孤傲的变革者
- MySQL的安全设定
- 过春节,坐汽车回家的朋友,注意了。。
- 记一次惨烈的电话面试题
- 《波斯王子-时之砂》精美图文攻略
- Git 远程仓库 git remote
- 陕西西安职高计算机学校有哪些,2019西安中职学校名单(含公办与民办名单)...
- 手机变Android麦克风,手机变麦克风
- 流利说 Level6 全文
- 修复华为移动服务器,移动app云服务器异常
- k8s安装 从k8s.gcr.io 拉取镜像失败
- 安装应用宝统一链接服务器,数据互通|安卓应用宝部分区服服务器数据互通维护公告...
- PHP 该网页无法正常运作情况原因记录 code 500
- 为什么燕子鸟纹身是如此出名
- 无人机航模电池上面有20C 30C,这是放电倍率