K-th occurrence HDU - 6704 (SA, 主席树)
大意: 给定串$s$, $q$个询问$(l,r,k)$, 求子串$s[l,r]$的第$k$次出现位置.
本来是个简单签到题, 可惜比赛的时候还没学$SA$...... 好亏啊
相同的子串在$SA$中是一定是连续的一段$[L,R]$
满足对于$L<i\le R$都有$h_i\ge r-l+1$
可以先用线段树二分出$L,R$, 然后主席树查询第$k$大即可
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
using namespace std;
const int N = 1e5+10;
int n, q, tot, a[N], T[N];
struct {int l,r,v;} tr[N*40];
char s[N];
int c[N],rk[N],h[N],sa[N],mi[N<<2]; void build(int *a, int n, int m) {
a[n+1] = 0;
int i,*x=rk,*y=h;
for(i=1;i<=m;i++) c[i]=0;
for(i=1;i<=n;i++) c[x[i]=a[i]]++;
for(i=1;i<=m;i++) c[i]+=c[i-1];
for(i=n;i;i--) sa[c[x[i]]--]=i;
for(int k=1,p;k<=n;k<<=1) {
p=0;
for(i=n-k+1;i<=n;i++) y[++p]=i;
for(i=1;i<=n;i++) if(sa[i]>k) y[++p]=sa[i]-k;
for(i=1;i<=m;i++) c[i]=0;
for(i=1;i<=n;i++) c[x[y[i]]]++;
for(i=1;i<=m;i++) c[i]+=c[i-1];
for(i=n;i;i--) sa[c[x[y[i]]]--]=y[i];
swap(x,y); x[sa[1]]=1; p=1;
for(i=2;i<=n;i++)
x[sa[i]]=(y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k])?p:++p;
if(p==n) break; m=p;
}
for(i=1;i<=n;i++) rk[sa[i]]=i;
for(int i=1,j,k=0;i<=n;i++){
if(k) k--;
j=sa[rk[i]-1];
while (a[i+k]==a[j+k]) k++;
h[rk[i]] = k;
}
}
//求最小的位置p, 使得[p,x]的最小值>=v
int find1(int o, int l, int r, int x, int v) {
if (r<=x) {
if (l==r) return mi[o]>=v?l:-1;
if (mi[rc]<v) return find1(rs,x,v);
int t = find1(ls,x,v);
return t==-1?mid+1:t;
}
if (mid>=x) return find1(ls,x,v);
int R = find1(rs,x,v);
if (R==-1||R>mid+1) return R;
int L = find1(ls,x,v);
return L==-1?R:L;
}
//求找最大的位置p, 使得[x,p]的最小值>=v
int find2(int o, int l, int r, int x, int v) {
if (x<=l) {
if (l==r) return mi[o]>=v?l:-1;
if (mi[lc]<v) return find2(ls,x,v);
int t = find2(rs,x,v);
return t==-1?mid:t;
}
if (mid<x) return find2(rs,x,v);
int L = find2(ls,x,v);
if (L==-1||L<mid) return L;
int R = find2(rs,x,v);
return R==-1?L:R;
}
int query(int u, int v, int l, int r, int k) {
if (l==r) return l;
int s = tr[tr[v].l].v-tr[tr[u].l].v;
if (s>=k) return query(tr[u].l,tr[v].l,l,mid,k);
return query(tr[u].r,tr[v].r,mid+1,r,k-s);
}
void add(int &o, int l, int r, int x) {
tr[++tot]=tr[o],o=tot,++tr[o].v;
if (l!=r) mid>=x?add(tr[o].l,l,mid,x):add(tr[o].r,mid+1,r,x);
}
int query(int p, int len, int k) {
int l = p>1?find1(1,2,n,p,len)-1:1;
int r = p<n?find2(1,2,n,p+1,len):n;
if (l<0) l = p;
if (r<0) r = p;
if (r-l+1>=k) return query(T[l-1],T[r],1,n,k);
return -1;
}
void build2(int o, int l, int r) {
if (l==r) return mi[o]=h[l],void();
build2(ls),build2(rs);
mi[o]=min(mi[lc],mi[rc]);
}
void brute_force() {
while (q--) {
int l, r, k;
scanf("%d%d%d",&l,&r,&k);
string g(s+l,s+r+1);
int pos = -1, cnt = 0;
REP(i,1,n) if (string(s+i,s+i+r-l+1)==g) {
if (++cnt==k) {
pos = i; break;
}
}
printf("%d\n", pos);
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d%d%s", &n, &q, s+1);
if (n<=10) {brute_force();continue;}
REP(i,1,n) a[i]=s[i]-'a'+1;
build(a,n,26);
build2(1,2,n);
REP(i,1,n) {
T[i] = T[i-1];
add(T[i],1,n,sa[i]);
}
while (q--) {
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
int len = r-l+1;
printf("%d\n", query(rk[l],r-l+1,k));
}
REP(i,0,n) T[i]=0;
while (tot) tr[tot].l=tr[tot].r=tr[tot].v=0,--tot;
}
}
K-th occurrence HDU - 6704 (SA, 主席树)的更多相关文章
- 2019CCPC网络赛 C - K-th occurrence HDU - 6704(后缀数组+ST表+二分+主席树)
题意 求区间l,r的子串在原串中第k次出现的位置. 链接:https://vjudge.net/contest/322094#problem/C 思路 比赛的时候用后缀自动机写的,TLE到比赛结束. ...
- HDU-6704 K-th occurrence(后缀数组+主席树)
题意 给一个长度为n的字符串,Q次询问,每次询问\((l,r,k)\) , 回答子串\(s_ls_{l+1}\cdots s_r\) 第\(k\) 次出现的位置,若不存在输出-1.\(n\le 1e5 ...
- 洛谷 P4094 [HEOI2016/TJOI2016]字符串(SA+主席树)
题面传送门 一道码农题---- u1s1 感觉这类题目都挺套路的,就挑个有代表性的题写一篇题解罢. 首先注意到答案满足可二分性,故考虑二分答案 \(mid\),转化为判定性问题. 考虑怎样检验 \(m ...
- Sequence II HDU - 5919(主席树)
Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,ana1,a2,⋯,anThere are ...
- Super Mario HDU - 4417 (主席树)
Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory ...
- 【10.10校内测试】【线段树维护第k小+删除】【lca+主席树维护前驱后驱】
贪心思想.将a排序后,对于每一个a,找到对应的删除m个后最小的b,每次更新答案即可. 如何删除才是合法并且最优的?首先,对于排了序的a,第$i$个那么之前就应该删除前$i-1$个a对应的b.剩下$m- ...
- 静态区间第K小(整体二分、主席树)
题目链接 题解 主席树入门题 但是这里给出整体二分解法 整体二分顾名思义是把所有操作放在一起二分 想想,如果求\([1-n]\)的第\(k\)小怎么二分求得? 我们可以二分答案\(k\), \(O(n ...
- HDU 3727 Jewel 主席树
题意: 一开始有一个空序列,然后有下面四种操作: Insert x在序列尾部加入一个值为\(x\)的元素,而且保证序列中每个元素都互不相同. Query_1 s t k查询区间\([s,t]\)中第\ ...
- 2019CCPC网络预选赛 1003 K-th occurrence 后缀自动机 + 二分 + 主席树
题意:给你一个长度为n的字符串,有m次询问,每次询问l到r的子串在原串中第k次出现的位置,如果没有输出-1.n, m均为1e5级别. 思路:后悔没学后缀数组QAQ,其实只要学过后缀数组这个题还是比较好 ...
随机推荐
- STM32 软件按键消抖
引言 通常按键所用的开关都是机械弹性开关,当机械触点断开.闭合时,由于机械触点的弹性作用,一个按键开关在闭合时不会马上就稳定的接通,在断开时也不会一下子彻底断开,而是在闭合和断开的瞬间伴随了一连串的抖 ...
- Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'kindergarten.n.stuMChkTime' which is not functionally dependent on columns in GROUP BY clause; this is in
错误原因: sql _mode中only _full _group _by不兼容的问题 解决思路: 既然是only _full _group _by不兼容,那就把它去掉就好啦 show var ...
- 微信小程序左滑删除未操作有复位效果
1.wxml <!--pages/test/test.wxml--> <view class="page"> <movable-area class= ...
- win10: ctrl+shift不能切换输入法的问题
习惯了使用Ctrl+Shift切换输入法,乍然切换到Win10,很不适应,可用以下方法修改之. 1. 点击开始菜单,点击“设置”按钮 2. 选择“时间与语言” 3. 选择“区域和语言”按钮,查看右 ...
- HDCMS多图字段的使用?
下面是HDCMS多图字段的简单使用: HDCMS在后台添加的多图,存到数据的时候是经过序列化过的,所以在使用的时候需要进行反序列化操作: $moreImg = M('keshi')->where ...
- windows下安装anaconda和tensorflow
anaconda确实很好用,省去了很多麻烦,现在我个人推荐直接使用anaconda. anaconda的特点:可以存在多个python环境,要使用某一个环境的话,就需要切换到这个环境,安装.卸载包都是 ...
- SeetaFace2 cmake VS2015编译编译
cmake Selecting Windows SDK version 10.0.17134.0 to target Windows 10.0.18362. == BUILD_VERSION: v2. ...
- python for 无限循环
class Infinit: def __iter__(self): return self def __next__(self): return None for i in Infinit(): p ...
- Spring cloud微服务安全实战-3-9API安全机制之审计日志
首先说一下审计日志的处理.审计日志处理的位置,应该是在认证之后,授权之前.因为只有你在认证之后,你才能知道这个请求到底是谁发出来的,谁在做这个事情.在这个授权之前,这样的话那些被拒绝掉的请求.在响应的 ...
- Spring Cloud微服务安全实战-1-1 课程导学