[2019CCPC网络赛][hdu6704]K-th occurrence(后缀数组&&主席树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6704
题意为查询子串s[l...r]第k次出现的位置。
写完博客后5分钟的更新
写完博客才发现这份代码和杭电的代码查重了....
为什么会变成这样呢?是我先交的,明明是我先交的…
激动!!第一次网络赛做出这种(板子)题。
首先求一下后缀数组的Height,我们知道Height数组表示两个排名相邻的后缀的最长公共前缀,则Height数组的区间最小值即为区间排名相邻的后缀的最长公共前缀。
我们想知道那些后缀包含了所查询的区间s[l...r]这样的前缀,则先找到s[l...n]这个后缀的排名,然后在包含这个排名的Height数组中找到最长的区间,且该区间最小值要大于等于r-l+1。即该区间内的后缀的最长公共前缀包含s[l...r]。
找这个最长的区间就可以分别二分左右端点,判断用ST表预处理Height数组,然后O(1)查询即可。
然后我们的任务就是在这个区间内找到第k小的位置。这个问题就可以对后缀数组的排名建主席树。然后查询即可。
#include<bits/stdc++.h>
#define lson l,mid,i<<1
#define rson mid+1,r,i<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2e5 + ;
int sa[maxn], tax[maxn], rak[maxn], tp[maxn], Height[maxn], lg[maxn];
int dp[maxn][];
int root[maxn], ls[maxn * ], rs[maxn * ], val[maxn * ], cnt;
char s[maxn];
void Qsort(int n, int m) {
for (int i = ; i < m; i++) tax[i] = ;
for (int i = ; i < n; i++) tax[rak[i]]++;
for (int i = ; i < m; i++) tax[i] += tax[i - ];
for (int i = n - ; i >= ; i--) sa[--tax[rak[tp[i]]]] = tp[i];
}
void suffix(int n, int m) {//n为原串长度+1,m为原串的种类
for (int i = ; i < n; i++)
rak[i] = s[i], tp[i] = i;
Qsort(n, m);
//debug();
for (int k = ; k <= n; k <<= ) {
int p = ;
for (int i = n - k; i < n; i++) tp[p++] = i;
for (int i = ; i < n; i++) if (sa[i] >= k) tp[p++] = sa[i] - k;
Qsort(n, m);
swap(rak, tp);
p = ;
rak[sa[]] = ;
for (int i = ; i < n; i++)
rak[sa[i]] = (tp[sa[i - ]] == tp[sa[i]] && tp[sa[i - ] + k] == tp[sa[i] + k]) ? p - : p++;
if (p >= n)
break;
m = p;
}
}
void getH(int n) {
int j, k = ;
for (int i = ; i <= n; i++)
rak[sa[i]] = i;
for (int i = ; i < n; i++) {
if (k)k--;
j = sa[rak[i] - ];
while (s[i + k] == s[j + k])
k++;
Height[rak[i]] = k;
}
}
void RMQ(int n) {
for (int i = ; i <= n; i++)
dp[i][] = Height[i];
for (int j = ; ( << j) <= n; j++) {
for (int i = ; i + ( << j) - <= n; i++)
dp[i][j] = min(dp[i][j - ], dp[i + ( << (j - ))][j - ]);
}
lg[] = -;
for (int i = ; i <= n; i++) {
if ((i&(i - )) == )
lg[i] = lg[i - ] + ;
else
lg[i] = lg[i - ];
}
}
int queryR(int l, int r) {
int k = lg[r - l + ];
return min(dp[l][k], dp[r - ( << k) + ][k]);
}
void build(int l, int r, int &i) {
i = ++cnt;
val[i] = ;
if (l == r)
return;
int mid = l + r >> ;
build(l, mid, ls[i]);
build(mid + , r, rs[i]);
}
void update(int k, int l, int r, int &i) {
ls[++cnt] = ls[i], rs[cnt] = rs[i], val[cnt] = val[i] + ;
i = cnt;
if (l == r)
return;
int mid = l + r >> ;
if (k <= mid)
update(k, l, mid, ls[i]);
else
update(k, mid + , r, rs[i]);
}
int query(int u, int v, int k, int l, int r) {
if (l == r)
return l;
int x = val[ls[v]] - val[ls[u]];
int mid = l + r >> ;
if (x >= k)
return query(ls[u], ls[v], k, l, mid);
else
return query(rs[u], rs[v], k - x, mid + , r);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n, q, cnt = ;
scanf("%d%d", &n, &q);
scanf("%s", s);
suffix(n + , );
getH(n);
for (int i = ; i <= n; i++)
++sa[i];
for (int i = n; i >= ; i--)
rak[i] = rak[i - ];
RMQ(n);
build(, n, root[]);
for (int i = ; i <= n; i++) {
root[i] = root[i - ];
update(sa[i], , n, root[i]);
}
//for (int i = 1; i <= n; i++)
// printf("%d%c", sa[i], i == n ? '\n' : ' ');
//for (int i = 1; i <= n; i++)
// printf("%d%c", rak[i], i == n ? '\n' : ' ');
//for (int i = 1; i <= n; i++)
// printf("%d%c", Height[i], i == n ? '\n' : ' ');
while (q--) {
int l, r, k, len;
scanf("%d%d%d", &l, &r, &k);
len = r - l + ;
int x = rak[l], y = rak[l];
int L = x + , R = n;
while (L <= R) {
int mid = L + R >> ;
if (queryR(L, mid) >= len)
y = mid, L = mid + ;
else
R = mid - ;
}
L = , R = x;
while (L <= R) {
int mid = L + R >> ;
if (queryR(mid, R) >= len)
x = mid - , R = mid - ;
else
L = mid + ;
}
//cout << x << " " << y << endl;
if (y - x + < k)
printf("-1\n");
else
printf("%d\n", query(root[x - ], root[y], k, , n));
}
}
}
[2019CCPC网络赛][hdu6704]K-th occurrence(后缀数组&&主席树)的更多相关文章
- HDU - 6704 K-th occurrence (后缀数组+主席树/后缀自动机+线段树合并+倍增)
题意:给你一个长度为n的字符串和m组询问,每组询问给出l,r,k,求s[l,r]的第k次出现的左端点. 解法一: 求出后缀数组,按照排名建主席树,对于每组询问二分或倍增找出主席树上所对应的的左右端点, ...
- HDU-6704 K-th occurrence(后缀数组+主席树)
题意 给一个长度为n的字符串,Q次询问,每次询问\((l,r,k)\) , 回答子串\(s_ls_{l+1}\cdots s_r\) 第\(k\) 次出现的位置,若不存在输出-1.\(n\le 1e5 ...
- 计蒜客 2019南昌邀请网络赛J Distance on the tree(主席树)题解
题意:给出一棵树,给出每条边的权值,现在给出m个询问,要你每次输出u~v的最短路径中,边权 <= k 的边有几条 思路:当时网络赛的时候没学过主席树,现在补上.先树上建主席树,然后把边权交给子节 ...
- BZOJ3473:字符串(后缀数组,主席树,二分,ST表)
Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串. Output 一 ...
- BZOJ4556:[TJOI\HEOI2016]字符串(后缀数组,主席树,二分,ST表)
Description 佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物.生日礼物放在一个神奇的箱子中.箱子外边写了一个长为n的字符串s,和m个问题.佳媛姐姐必须正确回答这m个问题,才能打开箱 ...
- [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...
- LOJ_#2720. 「NOI2018」你的名字 _后缀数组+主席树+倍增
题面: https://loj.ac/problem/2720 考虑枚举T串的每个后缀i,我们要做两件事. 一.统计有多少子串[i,j]在S中要求位置出现. 二.去重. 第二步好做,相当于在后缀数组上 ...
- P5346 【XR-1】柯南家族(后缀数组+主席树)
题目 P5346 [XR-1]柯南家族 做法 聪明性是具有传递性的,且排列是固定的 那么先预处理出每个点的名次,用主席树维护\(k\)大值 一眼平衡树,遍历的同时插入\(O(log^2n)\),总时间 ...
- BZOJ 5496: [2019省队联测]字符串问题 (后缀数组+主席树优化建图+拓扑排序)
题意 略 分析 考场上写了暴力建图40分溜了-(结果只得了30分) 然后只要优化建边就行了 首先给出的支配关系无法优化,就直接A向它支配的B连边. 考虑B向以B作为前缀的所有A连边,做一遍后缀数组,两 ...
随机推荐
- redis面试题集錦
1为什么Redis需要把所有数据放到内存中? Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘.所以Redis具有快速和数据持久化的特性.如果不将数据放到内存中,磁盘 ...
- man---中英文翻译
一. 总览---SYNOPSIS 二.
- 花式赋值、列表、字典、解压缩、input()、格式化学习笔记
目录 花式赋值 列表(list) 字典(dict) 解压缩 input()与用户交互 格式化的三种方式 f_String格式化(important) %s.%d占位符 format 格式化(不常用) ...
- UTC和GMT
UTC GMT UTC = Coordinated Universal Time. 中文名称为协调世界时. GMT = Greenwich Mean Time. 中文名称为格林尼治(平)时 UTC = ...
- STM32开发板的TIM3开启和关闭
关闭定时器中断要考虑好多情况 1)关闭定时器时,定时器是否在处在工作状态 2)关闭定时器时,定时器是否正好进入中断,造成关闭程序出现断层,进而无法实现完整关闭程序,此时可以使用高一级别的外部中断强制进 ...
- mysql TOP语句 语法
mysql TOP语句 语法 作用:用于规定要返回的记录的数目. 语法:SELECT column_name(s) FROM table_name LIMIT number 说明:对于拥有数千条记录的 ...
- ASP.NET的OnClientClick与OnClick事件
OnClientClick是客户端事件方法.一般采用JavaScript来进行处理.也就是直接在IE端运行.一点击就运行. OnClick事件是服务器端事件处理方法,在服务器端,也就是IIS中运行.点 ...
- 【bzoj1927】[Sdoi2010]星际竞速
题目描述: 10 年一度的银河系赛车大赛又要开始了.作为全银河最盛大的活动之一, 夺得这个项目的冠军无疑是很多人的梦想,来自杰森座 α星的悠悠也是其中之一. 赛车大赛的赛场由 N 颗行星和M条双向星际 ...
- 3D Computer Grapihcs Using OpenGL - 09 Enable Depth Test
启用Depth Test OpenGL是个3D绘图API,也就是说不只有xy坐标轴,还有第三个坐标轴z,z轴的方向是垂直于屏幕,指向屏幕内. 靠近人眼的方向是负方向,标准化设备坐标的最小值是-1, 最 ...
- 尚硅谷Docker---1-5、docker简介
尚硅谷Docker---1-5.docker简介 一.总结 一句话总结: docker是环境打包:有点像windows镜像 docker的实质:缩小版.精细版.高度浓缩版的一个小型的linux系统 1 ...