[传送门]

先求出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. ZYNQ笔记(6):普通自定义IP封装实现PL精准定时中断

    软件的定时中断很难控制精准触发沿的位置,可以通过 PL-PS 的中断完成精准的定时中断.PL 的中断通过 Verilog 代码产生,这样紧密结合 PS-PL 的处理,发挥各自的优势. 一.PL 侧定时 ...

  2. 如何选择CPU

    一.品牌: 选择哪家公司的处理器,AMD公司和inter公司的处理器相比较,AMD在三维制作.游戏应用.和视频处理方面突出,inter的处理器在商业应用.多媒体应用.平面设计方面有优势,性能方面,同档 ...

  3. ASP.NET Core应用程序的参数配置及使用(转载)

    本文结构 提前准备 参数配置方式 appsettings.json 环境变量 命令行参数 在控制器中使用配置参数 注入IConfiguration对象 注入IOptions对象 总结 应用程序的开发不 ...

  4. List泛型用法(转载)

    网上的List泛型用法,未验证,目测基本正确,教学用资料. 1.  List的基础.常用方法: 声明: 1.List<T> mList = new List<T>(); T为列 ...

  5. Advanced-REST-client 获取及安装

    作为一个java开发人员,大家或多或少的要写或者接触一些http接口.而当我们需要本地调试接口常常会因为没有一款好用的工具而烦恼.今天要给大家介绍一款非常好用.实用且方便的http接口测试工具. 获取 ...

  6. @Valid注解的使用springmvc pojo校验

    @Valid注解用于校验,所属包为:javax.validation.Valid. ① 首先需要在实体类的相应字段上添加用于充当校验条件的注解,如:@Min,如下代码(age属于User类中的属性): ...

  7. PHP面试题2019年腾讯工程师面试题和答案

    一.单选题(共29题,每题5分) 1.PHP执行的时候有如下执行过程:Scanning(Lexing) - Compilation - Execution - Parsing,其含义分别为: A.将P ...

  8. JavaScript---Dom树详解,节点查找方式(直接(id,class,tag),间接(父子,兄弟)),节点操作(增删改查,赋值节点,替换节点,),节点属性操作(增删改查),节点文本的操作(增删改查),事件

    JavaScript---Dom树详解,节点查找方式(直接(id,class,tag),间接(父子,兄弟)),节点操作(增删改查,赋值节点,替换节点,),节点属性操作(增删改查),节点文本的操作(增删 ...

  9. selenium firefox 内存 速度优化

    selenium firefox 内存 速度优化 2 23 profile = webdriver.FirefoxProfile() 2 24 profile.set_preference(" ...

  10. promiseall的使用场景

    在上图中点击诊断后下方的图标会一次进行数据请求,根据请求回来的数据显示正常异常,在请求数据完成期间再次点击诊断不触发事件 let p1 = new Promise((resolve, reject) ...