[传送门]

先求出SA和height。然后找到 rank[l] 的 height 值。能成为相同子串的就是和rank[l]的lcp不小于 $len$ 的。二分出左右端点之后,主席树求第k小即可。

#include <bits/stdc++.h>

const int N = 1e5 + ;
char s[N];
int n, q; namespace SA {
int sa[N], rk[N], fir[N], sec[N], c[N], height[N];
int mn[N][], lg[N];
void build(int len, int num = ) {
register int i, j, k;
for (i = ; i <= num; i++) c[i] = ;
for (i = ; i <= len; i++) ++c[fir[i] = s[i]];
for (i = ; i <= num; i++) c[i] += c[i - ];
for (i = len; i >= ; i--) sa[c[fir[i]]--] = i;
for (k = ; k <= len; k <<= ) {
int cnt = ;
for (i = len - k + ; i <= len; i++) sec[++cnt] = i;
for (i = ; i <= len; i++) if (sa[i] > k) sec[++cnt] = sa[i] - k;
for (i = ; i <= num; i++) c[i] = ;
for (i = ; i <= len; i++) ++c[fir[i]];
for (i = ; i <= num; i++) c[i] += c[i - ];
for (i = len; i >= ; i--) sa[c[fir[sec[i]]]--] = sec[i], sec[i] = ;
std::swap(fir, sec);
fir[sa[]] = ; cnt = ;
for (i = ; i <= len; i++)
fir[sa[i]] = (sec[sa[i]] == sec[sa[i - ]] && sec[sa[i] + k] == sec[sa[i - ] + k]) ? cnt : ++cnt;
if (cnt == len) break;
num = cnt;
}
k = ;
for (i = ; i <= len; i++) rk[sa[i]] = i;
for (i = ; i <= len; i++) {
if (rk[i] == ) continue;
if (k) k--;
j = sa[rk[i] - ];
while (j + k <= len && i + k <= len && s[i + k] == s[j + k]) k++;
height[rk[i]] = k;
}
} inline int MIN(int a, int b) {
return height[a] < height[b] ? a : b;
} void init_RMQ(int n) {
for (int i = , j = ; i <= n; i++)
lg[i] = ( << (j + )) == i ? ++j : j;
for (int i = ; i <= n; i++)
mn[i][] = i;
for (int j = ; j < ; j++)
for (int i = ; i + ( << j) - <= n; i++)
mn[i][j] = MIN(mn[i][j - ], mn[i + ( << (j - ))][j - ]);
} int RMQ(int a, int b) {
int log = lg[b - a + ];
b -= ( << log) - ;
return MIN(mn[a][log], mn[b][log]);
} int LCP(int i, int j) {
i = rk[i], j = rk[j];
if (i > j) std::swap(i, j);
return height[RMQ(i + , j)];
}
} int root[N]; struct Seg {
struct Tree {
int lp, rp, sum;
} tree[N * ];
int tol;
inline void clear() {
tol = ;
memset(tree, , sizeof(tree));
}
void update(int &p, int q, int l, int r, int pos) {
tree[p = ++tol] = tree[q];
tree[p].sum++;
if (l == r) return;
int mid = l + r >> ;
if (pos <= mid) update(tree[p].lp, tree[q].lp, l, mid, pos);
else update(tree[p].rp, tree[q].rp, mid + , r, pos);
}
int query(int p, int q, int l, int r, int k) {
if (l == r) return l;
int mid = l + r >> ;
int sum = tree[tree[p].lp].sum - tree[tree[q].lp].sum;
if (sum >= k) return query(tree[p].lp, tree[q].lp, l, mid, k);
return query(tree[p].rp, tree[q].rp, mid + , r, k - sum);
}
} seg; int solve(int x, int y, int k) {
int len = y - x + ;
int L = SA::rk[x];
if (SA::height[L] >= len) {
int l = , r = L;
while (l <= r) {
int mid = l + r >> ;
if (SA::LCP(SA::sa[mid], x) >= len) L = mid, r = mid - ;
else l = mid + ;
}
}
int R = SA::rk[x];
if (SA::height[SA::rk[x] + ] >= len) {
int l = SA::rk[x] + , r = n;
while (l <= r) {
int mid = l + r >> ;
if (SA::LCP(x, SA::sa[mid]) >= len) R = mid, l = mid + ;
else r = mid - ;
}
}
//printf("%d %d\n", L, R);
if (k > seg.tree[root[R]].sum - seg.tree[root[L - ]].sum) return -;
return seg.query(root[R], root[L - ], , n, k);
} int main() {
freopen("in.txt", "r", stdin);
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &q);
scanf("%s", s + );
SA::build(n);
SA::init_RMQ(n);
seg.clear();
for (int i = ; i <= n; i++)
seg.update(root[i], root[i - ], , n, SA::sa[i]);
while (q--) {
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
printf("%d\n", solve(l, r, k));
}
}
return ;
}

HDU6704 K-th occurrence的更多相关文章

  1. django模型操作

    Django-Model操作数据库(增删改查.连表结构) 一.数据库操作 1.创建model表        

  2. HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)

    layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...

  3. HDU-6704 K-th occurrence

    Description You are given a string S consisting of only lowercase english letters and some queries. ...

  4. [2019CCPC网络赛][hdu6704]K-th occurrence(后缀数组&&主席树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6704 题意为查询子串s[l...r]第k次出现的位置. 写完博客后5分钟的更新 写完博客才发现这份代码 ...

  5. hdu6704 2019CCPC网络选拔赛1003 K-th occurrence 后缀自动机+线段树合并

    解题思路: fail树上用权值线段树合并求right/endpos集合,再用倍增找到待查询串对应节点,然后权值线段树求第k大. #include<bits/stdc++.h> using ...

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

    题意:给你一个长度为n的字符串,有q个询问,每次询问一个子串s(l,r)第k次出现的位置,若子串出现次数少于k次输出-1. 解题思路:先把SA跑出来,然后对于每次询问可以由l和rank[]找到l在所有 ...

  7. HDU-6704 K-th occurrence(后缀数组+主席树)

    题意 给一个长度为n的字符串,Q次询问,每次询问\((l,r,k)\) , 回答子串\(s_ls_{l+1}\cdots s_r\) 第\(k\) 次出现的位置,若不存在输出-1.\(n\le 1e5 ...

  8. [转]vi command summary

    The following tables contain all the basic vi commands. *Starting vi* Command Description vi file st ...

  9. LeetCode 560. Subarray Sum Equals K (子数组之和等于K)

    Given an array of integers and an integer k, you need to find the total number of continuous subarra ...

随机推荐

  1. django开发_七牛云CNAME解析

    CNAME 简介 CNAME 即指别名记录,也被称为规范名字.这种记录允你将多个名字映射到同一台计算机. 当需要将域名指向另一个域名,再由另一个域名提供 ip地址,就需要添加 CNAME 记录. 为什 ...

  2. 『异或粽子 堆 可持久化trie』

    异或粽子 Description 小粽是一个喜欢吃粽子的好孩子.今天她在家里自己做起了粽子. 小粽面前有 n 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 1 到 n.第 i 种馅儿 ...

  3. 【LeetCode】633. Sum of Square Numbers

    Difficulty: Easy  More:[目录]LeetCode Java实现 Description https://leetcode.com/problems/sum-of-square-n ...

  4. HTML+CSS+JS综合练习(动态验证版)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. 一张图看懂SharpBarcode

    通过下面的图片,可以瞬间看懂整个SharpBarcode类库的脉络.

  6. Java自学-异常处理 异常分类

    Java 中异常的分类 异常分类: 可查异常,运行时异常和错误3种 其中,运行时异常和错误又叫非可查异常 步骤 1 : 可查异常 可查异常: CheckedException 可查异常即必须进行处理的 ...

  7. English--名词从句

    English|名词从句 现在开始讲述关于名词从句的内容.从句大家都不陌生,但是学习了那么多年,什么是从句?接下来让我们一起来看看. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知 ...

  8. 手写Ajax的意义所在,从青铜到钻石!

    话说菩提祖师打了孙猴子三板子  然后悟空学会72般变化以及一身神通 对待这个问题作为面试者要思考更加深层次的意义 才更能获得认可 实际上写的ajax 很能看出一个的水平 贴几段代码就可以看出水平的高低 ...

  9. 【转载】 Windows系统电脑通过设备管理器查看电脑配置信息

    在采购电脑或者使用电脑的过程中,有时候我们需要查看到电脑的所有设备硬件信息,此时就可以通过Windows系统自带的设备管理器界面来查看该电脑所有的设备配置信息,包括CPU型号频率.内存.硬盘型号以及容 ...

  10. jquery如何监听浏览器窗口大小并根据不同的大小输出不同的值

    $(window).bind("load resize",function(){ document.documentElement.clientWidth >= 600 ? ...