K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)
大意: 给定串s, q个询问(l,r,k), 求子串s[l,r]的第kk次出现位置.
这是一篇很好的题解:
https://blog.csdn.net/sdauguanweihong/article/details/100063096
加点个人:
我对上面的题解更为详细的解释下:
后缀数组处理出来的heigth[] 数组 有个这样的性质:
对于排名 a 的后缀字符串 与排名 b 的后缀字符串 ,他们的最长公共前缀的长度为 min{heigth[a+1],heigth[a+2],heigth[b]};
依据这样的性质就可以二分线段树出[l,r] 这个字符串 是在多少排名的区间[L,R]了;
注意:我本想贪图方便用先二分l然后判断[l,pos] 的最小值复杂度为log*log 这个会T的
所以找这个区间要用log的方法,就是在存了最小值的线段树里面去搜左孩子啊右孩子什么的
- #include<bits/stdc++.h>
- using namespace std;
- #define INF 0x3f3f3f3f
- const int maxn = ;
- char s[maxn];
- int y[maxn],x[maxn],c[maxn],sa[maxn],rk[maxn],height[maxn],wt[];
- int n,k,q;
- int get_SA(int m){
- for(int i= ; i<=m ; i++) c[i]=;
- for(int i= ; i<=n ; i++) sa[i]=;
- for(int i= ; i<=n ; i++) ++c[x[i]=s[i]];
- for(int i= ; i<=m ; i++) c[i]+=c[i-];
- for(int i=n ; i>= ; i--) sa[c[x[i]]--]=i;
- for(int k= ; k<=n ; k<<=){
- int num=;
- for(int i=n-k+ ; i<=n ; i++) y[++num]=i;
- for(int i= ; i<=n ; i++) if(sa[i]>k) y[++num]=sa[i]-k;
- for(int i= ; i<=m ; i++) c[i]=;
- for(int i= ; i<=n ; i++) ++c[x[i]];
- for(int i= ; i<=m ; i++) c[i]+=c[i-];
- for(int i=n ; i>= ; i--) sa[c[x[y[i]]]--]=y[i],y[i]=;
- swap(x,y);
- x[sa[]]=;
- num=;
- for(int i= ; i<=n ; i++)
- x[sa[i]]=(y[sa[i]]==y[sa[i-]] && y[sa[i]+k]==y[sa[i-]+k]) ? num : ++num;
- if (num==n) break;
- m=num;
- }
- }
- int get_height() {
- int k=;
- for (int i=; i<=n; ++i) rk[sa[i]]=i;
- for (int i=; i<=n; ++i) {
- if (rk[i]==) continue;
- if (k) --k;
- int j=sa[rk[i]-];
- while (j+k<=n && i+k<=n && s[i+k]==s[j+k]) ++k;
- height[rk[i]]=k;
- }
- }
- int mi[maxn<<];
- void pushup(int rt){
- mi[rt]=min(mi[rt<<],mi[rt<<|]);
- }
- void build(int l,int r,int rt)
- {
- if ( l==r )
- {
- mi[rt]=height[l];
- return ;
- }
- int m = (l+r) >> ;
- build(l,m,rt<<);
- build(m+,r,rt<<|);
- pushup(rt);
- }
- int solvel(int o , int l , int r , int x , int v){
- int mid=(l+r)>>;
- if(r<=x){
- if(l==r) return mi[o]>=v?l:-;
- if(mi[o<<|]<v) return solvel(o<<|,mid+,r,x,v);
- int t=solvel(o<<,l,mid,x,v);
- return t==-?mid+:t;
- }
- if(mid>=x) return solvel(o<<,l,mid,x,v);
- int R=solvel(o<<|,mid+,r,x,v);
- if (R==-||R>mid+) return R;
- int L = solvel(o<<,l,mid,x,v);
- return L==-?R:L;
- }
- int solver(int o, int l, int r, int x, int v){
- int mid=(l+r)>>;
- if (x<=l) {
- if (l==r) return mi[o]>=v?l:-;
- if (mi[o<<]<v) return solver(o<<,l,mid,x,v);
- int t = solver(o<<|,mid+,r,x,v);
- return t==-?mid:t;
- }
- if (mid<x) return solver(o<<|,mid+,r,x,v);
- int L = solver(o<<,l,mid,x,v);
- if (L==-||L<mid) return L;
- int R = solver(o<<|,mid+,r,x,v);
- return R==-?L:R;
- }
- int tot;
- int lson[maxn<<],rson[maxn<<],T[maxn],cc[maxn<<];
- void zhu_build(int &root,int l,int r)
- {
- root=++tot;
- if ( l==r ) return;
- int mid=(l+r)/;
- zhu_build(lson[root],l,mid);
- zhu_build(rson[root],mid+,r);
- }
- void update(int root,int &rt,int p,int val,int l,int r)
- {
- rt=++tot;
- lson[rt]=lson[root],rson[rt]=rson[root];
- cc[rt]=cc[root]+val;
- if ( l==r ) return;
- int mid=(l+r)/;
- if ( p<=mid ) update(lson[rt],lson[rt],p,val,l,mid);
- else update(rson[rt],rson[rt],p,val,mid+,r);
- }
- int query(int rt_,int rt,int l,int r,int k)
- {
- if ( l==r ) return l;
- int mid=(l+r)/;
- int sum=cc[lson[rt_]]-cc[lson[rt]];
- if ( sum>=k ) return query(lson[rt_],lson[rt],l,mid,k);
- else return query(rson[rt_],rson[rt],mid+,r,k-sum);
- }
- int main(){
- int _;scanf("%d",&_);
- while(_--){
- scanf("%d%d%s",&n,&q,s+);
- get_SA();
- get_height();
- build(,n,);
- tot=;
- zhu_build(T[],,n);
- for(int i= ; i<=n ; i++){
- update(T[i-],T[i],sa[i],,,n);
- }
- while(q--){
- int l,r;scanf("%d%d%d",&l,&r,&k);
- int p=rk[l];
- int ql = p>?solvel(,,n,p,r-l+)-:;
- int qr = p<n?solver(,,n,p+,r-l+):n;
- if (ql<) ql = p;
- if (qr<) qr = p;
- int ans;
- if(qr-ql+<k)
- ans=-;
- else
- ans=query(T[qr],T[ql-],,n,k);
- printf("%d\n",ans);
- }
- }
- }
K-th occurrence HDU - 6704 (后缀数组+二分线段树+主席树)的更多相关文章
- HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given ...
- [CSP-S模拟测试]:platform(后缀数组+二分+线段树)
题目传送门 题目描述 走过奈何桥有一个名叫望乡台的土台,望乡台有个名曰孟婆的老妇人在卖孟婆汤.一生爱恨情仇,一世浮沉得失,都可以随这碗孟婆汤遗忘得干干净净.现在有$n$碗孟婆汤摆成一排,汤的品种不超过 ...
- HDU 5558 后缀数组+二分
题意有一些绕,但其实就是对于不断变化的i,求以j(0=j<i)使得suffix[j]与suffix[i]的最长公共前缀最长,如果有多个j,则取最小的j. 可以在rank数组中二分,在1-rank ...
- UVA-11107 Life Forms(求出现K次的子串,后缀数组+二分答案)
题解: 题意: 输入n个DNA序列,你的任务是求出一个长度最大的字符串,使得它在超过一半的DNA序列中出现.如果有多解,按照字典序从小到大输入所有解. 把n个DNA序列拼在一起,中间用没有出现过的字符 ...
- BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )
二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...
- hdu 3948 后缀数组
The Number of Palindromes Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 262144/262144 K (J ...
- 【bzoj4310】跳蚤 后缀数组+二分
题目描述 很久很久以前,森林里住着一群跳蚤.一天,跳蚤国王得到了一个神秘的字符串,它想进行研究. 首先,他会把串分成不超过 k 个子串,然后对于每个子串 S,他会从S的所有子串中选择字典序最大的那一个 ...
- BZOJ 1717 [USACO06DEC] Milk Patterns (后缀数组+二分)
题目大意:求可重叠的相同子串数量至少是K的子串最长长度 洛谷传送门 依然是后缀数组+二分,先用后缀数组处理出height 每次二分出一个长度x,然后去验证,在排序的后缀串集合里,有没有连续数量多于K个 ...
- POJ 1743 [USACO5.1] Musical Theme (后缀数组+二分)
洛谷P2743传送门 题目大意:给你一个序列,求其中最长的一对相似等长子串 一对合法的相似子串被定义为: 1.任意一个子串长度都大于等于5 2.不能有重叠部分 3.其中一个子串可以在全部+/-某个值后 ...
随机推荐
- Linear Discriminant Analysis
Suppose that we model each class density as multivariate Gaussian, in practice we do not know the pa ...
- [LeetCode] 210. 课程表 II
题目链接:https://leetcode-cn.com/problems/course-schedule-ii/ 题目描述: 现在你总共有 n 门课需要选,记为 0 到 n-1. 在选修某些课程之前 ...
- Java8与JDK8和JDK1.8有什么区别?
JDK版本与发行时间 版本 名称 发行日期 JDK 1.0 Oak(橡树) 1996-01-23 JDK 1.1 none(无) 1997-02-19 JDK 1.1.4 Sparkler(宝石) 1 ...
- Lucene整理--中文分词
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/hai_cheng001/article/details/37511379 看lucene主页(htt ...
- vue项目引入外部字体
1.UI设计图有"华文黑体",担心客户端没有该字体,将"huawen.ttf"字体文件,放入项目中: 2.创建一个font.scss(或font.css)文件: ...
- netperf编译./configure时报错 "error: cannot guess build type;you nust specify one"
问题: 解决办法-亲测可用: 尝试:./configure --build=mingw提示无法辨别 checking build system type... Invalid configuratio ...
- mpg123 - 播放 MPEG 1.0/2.0 Layer-1, -2, -3 音频文件
语法 mpg123 [ -tscvqy01m24 ][ -b size ][ -k num ][ -n num ][ -f factor ][ -r rate ][ -g gain ][ -a dev ...
- Linux架构--------Rsync守护进程推和拉
一.Rsync基本概述 rsync是一款开源.快速.多功能.可实现全量及增量的本地或远程数据同步备份的优秀工具.rsync软件适用于Unix/linux/Windows等多种操作系统平台. 二.Rsy ...
- Vscode添加谷歌Debug插件
1. 2.安装好 Debugger for Chrome之后,找到要进行Debug的文件 3. 4.进入到launch.json文件中进行相应的配置 配置文件内容如下: { "version ...
- POJ 1966 Cable TV Network (最大流最小割)
$ POJ~1966~Cable~TV~Network $ $ solution: $ 第一眼可能让人很难下手,但本就是冲着网络流来的,所以我们直接一点.这道题我们要让这个联通图断开,那么势必会有两个 ...