HDU6704 K-th occurrence
[传送门]
先求出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的更多相关文章
- django模型操作
Django-Model操作数据库(增删改查.连表结构) 一.数据库操作 1.创建model表
- HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)
layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...
- HDU-6704 K-th occurrence
Description You are given a string S consisting of only lowercase english letters and some queries. ...
- [2019CCPC网络赛][hdu6704]K-th occurrence(后缀数组&&主席树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6704 题意为查询子串s[l...r]第k次出现的位置. 写完博客后5分钟的更新 写完博客才发现这份代码 ...
- hdu6704 2019CCPC网络选拔赛1003 K-th occurrence 后缀自动机+线段树合并
解题思路: fail树上用权值线段树合并求right/endpos集合,再用倍增找到待查询串对应节点,然后权值线段树求第k大. #include<bits/stdc++.h> using ...
- hdu6704 2019CCPC网络选拔赛1003 K-th occurrence 后缀数组
题意:给你一个长度为n的字符串,有q个询问,每次询问一个子串s(l,r)第k次出现的位置,若子串出现次数少于k次输出-1. 解题思路:先把SA跑出来,然后对于每次询问可以由l和rank[]找到l在所有 ...
- HDU-6704 K-th occurrence(后缀数组+主席树)
题意 给一个长度为n的字符串,Q次询问,每次询问\((l,r,k)\) , 回答子串\(s_ls_{l+1}\cdots s_r\) 第\(k\) 次出现的位置,若不存在输出-1.\(n\le 1e5 ...
- [转]vi command summary
The following tables contain all the basic vi commands. *Starting vi* Command Description vi file st ...
- 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 ...
随机推荐
- Spring Security 解析(四) ——短信登录开发
Spring Security 解析(四) -- 短信登录开发 在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决定先把Spring Security ...
- 给Go程序加入编译版本时间等信息
先看效果 $./myapp -v GitCommitLog=d97d098e5bb4ad38a2a7968f273a256e10a0108f mod bininfo comment GitStatus ...
- DDR3(2):初始化
调取 DDR3 IP核后,是不能直接进行读写测试的,必须先进行初始化操作,对 IP 核进行校验.本篇采用 Modelsim 软件配合 DDR3 IP核生成的仿真模型,搭建出 IP核的初始化过程. 一. ...
- ubuntn18 docker zabbix+grafana安装和使用
在ubuntu docker inflxudb(安装 使用 备份 还原 以及python编码) telegraf Grafana我采用telegraf采集数据, 本文计划采用zabbix来才采集数据, ...
- centos7安装mysql初始化报错
[root@localhost bin]# ./mysqld --initialize --user=mysql2019-09-16T06:15:28.835202Z 0 [Warning] TIME ...
- MOOC 编译原理笔记(一):编译原理概述以及程序设计语言的定义
编译原理概述 什么是编译程序 编译程序指:把某一种高级语言程序等价地转换成另一张低级语言程序(如汇编语言或机器代码)的程序. 高级语言程序-翻译->机器语言程序-运行->结果. 其中编译程 ...
- WebAPI中路由参数中包含字符-点“.”
请求url都是类似:/api/area/province.list 我们默认建立的Asp Net WebApi 服务时,如果请求url包含“.”,则返回404错误. 解决办法:需要在web.confi ...
- 使用Nexus3搭建Maven私服+上传第三方jar包到本地maven仓库
1.搭建Maven私服背景 公司还是按捺不住,要搭建一个自己的Maven本地仓库,可以让开发人员down架包,从内网还是快很多. 这样公司的maven本地仓库就是 开发人员自己电脑上的maven仓库 ...
- pyspider最佳实践
pyspider是好东西,非常稳定,很久很久以前架了一个,心冷了一段时间,但人家尽忠职守地持续运行,一直在抓取东西. 结合chrome,抓取代码简直不要太好写,没想到,最头大的,还是它的调度.明明感觉 ...
- 4.Javascript中实现继承的几种方法及其优缺点
要搞懂JS继承,我们首先要理解原型链:每一个实例对象都有一个__proto__属性(隐式原型),在js内部用来查找原型链:每一个构造函数都有prototype属性(显示原型),用来显示修改对象的原型, ...