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 ...
随机推荐
- Vim 入门教程
Vim 入门教程 转载请保留以上信息 Vim 的教程相对比较零散,系统的教程比较少,我也阅读过不少教程,走过很 多弯路.借着 Vim-china 组织组建这一契机,整理下自己学习过的内容, 分享给大家 ...
- Android开发遇到的一些小问题
1.文件下载时,默认只能用https,怎么用http协议: 在Manifest.xml文件中增加一个配置项: android:usesCleartextTraffic="true" ...
- ElasticSearch 线程池类型分析之 ResizableBlockingQueue
ElasticSearch 线程池类型分析之 ResizableBlockingQueue 在上一篇文章 ElasticSearch 线程池类型分析之 ExecutorScalingQueue的末尾, ...
- R语言dataframe的常用操作总结
前言:近段时间学习R语言用到最多的数据格式就是data.frame,现对data.frame常用操作进行总结,其中函数大部分来自dplyr包,该包由Hadley Wickham所作,主要用于数据的清洗 ...
- QT之类型转换
Qt在进行数据类型转换时,容易忘记如何使用,或者是早已厌倦了百度QString转QByteArray,QByteArray转char,QString转string....... 现在分享一篇QT数据类 ...
- (10)ASP.NET Core 中的环境(Environments:dev, stage, prod)
1.环境变量配置 ASP.NET Core在应用程序启动时读取环境变量(Properties\launchSettings.json)ASPNETCORE_ENVIRONMENT,并将该值存储在IHo ...
- Kafka学习笔记之如何永久删除Kafka的Topic
0x00 问题描述 使用kafka-topics --delete命令删除topic时并没有真正的删除,而是把topic标记为:“marked for deletion”,导致重新创建相同名称的Top ...
- VIM编辑器使用的小技巧
在命令中输入 vi –t 类型名.结构体名或者函数名 系统就会寻找相应的对象,默认是在当前目录的 tags 中搜索,例如我们想寻找 stat 结构体, 则输入 vi –t stat 然后按 q 退出 ...
- 走一次HashMap的存取
忘了太多东西,好好复习. 存: if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length;//检查 ...
- jquery问题,如何调用带this的函数?
这样写: 1 2 3 4 5 6 7 8 9 10 11 12 $(".aa").on("mouseout",function(){ var obj = ...