HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)
layout: post
title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- kuangbin
- 字符串
" target="_blank" style="font-size:24px;">传送门
题意
给出一个长度为\(n\)字符串\(s\), \(m\)次询问,每次问你字符串\(s\)区间内的字符串\(l,r\)第\(k\)次出现的位置。
思路
比赛的时候一眼就知道是\(sa\)但是对于\(sa\)实在不喜欢,于是比赛的时候整场用\(sam\)硬怼。已经想到了用主席树记录\(endpos\)位置,然后从后往前推过去,但是比赛时还不会在\(sam\)上玩权值线段树合并,赛后学习了一下。
首先,这题我们可以在\(sam\)上的每个新开节点上存储这个节点是在原串的那个位置是把。
然后对于一个串\(i\)他的\(father\)肯定是他的\(后缀\) 所以他的\(endpos\)肯定也是他\(father\)的\(endpos\)
同时一个\(father\)不仅仅只有\(i\)这个儿子 所以\(father\)的继承是从很多儿子那边的来的,于是我们需要搞笑处理继承效果,这里用到了权值线段树合并,线段树下标是\(endpos\)在\(s\)的位置。
这样我们就可以通过找到一个点而得出这个点所有的\(endpos\) ,也可以很快的在权值线段树中找到第\(k\)大的$endpos \(。但是\)Q$次查询每次都可能用一个长度\(1e5\)的串进入\(sam\)中找这个点的位置,于是我们考虑离线操作,将询问按照\(r\)排序。但是我们找到了一个点之后可能这个长度太大了,于是我们需要跳到这个点的\(father\) 知道这个点的长度刚好大于等于我们需要的长度,这样答案才完整。因为\(father\)的长度是单调的,于是我们可以考虑用树上倍增 快速找到合适的\(father\)。
于是这题就愉快的结束了。真爽啊。debug都不需要。
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int maxn=5e5+50;
int ls[maxn*80],rs[maxn*80],rt[maxn*80],sum[maxn*80],cnt;
void update(int &o,int l,int r,int pos){
if(!o)o=++cnt;
if(l==r){
sum[o]++;return;
}
int mid=(l+r)/2;
if(pos<=mid)update(ls[o],l,mid,pos);
else update(rs[o],mid+1,r,pos);
sum[o]=sum[ls[o]]+sum[rs[o]];
}
int merger(int o,int pre,int l,int r){
if(!o)return pre;if(!pre)return o;
int k=++cnt;
if(l==r){
sum[k]=sum[o]+sum[pre];
return k;
}int mid=(l+r)/2;
ls[k]=merger(ls[o],ls[pre],l,mid);
rs[k]=merger(rs[o],rs[pre],mid+1,r);
sum[k]=sum[ls[k]]+sum[rs[k]];
return k;
}
int query(int o,int l,int r,int k){
if(sum[o]<k)return -1;
if(l==r)return l;
int mid=(l+r)/2;
if(sum[ls[o]]>=k)return query(ls[o],l,mid,k);
else return query(rs[o],mid+1,r,k-sum[ls[o]]);
}
struct Q{
int l,r,k,id;
bool operator<(const Q &o)const{
return r<o.r;
}
}my[maxn];
int n;
char s[maxn];
int ans[maxn];
struct SAM{
int fa[maxn],ch[maxn][26],maxlen[maxn],tot,last;
int sz[maxn],a[maxn],b[maxn];
void init(){
cnt=0;
fill(rt,rt+n*80,0);
fill(ls,ls+n*80,0);
fill(rs,rs+n*80,0);
fill(sum,sum+n*80,0);
tot=last=1;maxlen[1]=fa[1]=0;
memset(ch[1],0,sizeof(ch[1]));
}
void add(int x,int id){
int np=++tot,p=last;last=np;update(rt[np],1,n,id);
maxlen[np]=maxlen[p]+1;sz[np]=1;
memset(ch[np],0,sizeof(ch[np]));
while(p&&!ch[p][x])ch[p][x]=np,p=fa[p];
if(!p)fa[np]=1;
else{
int q=ch[p][x];
if(maxlen[q]==maxlen[p]+1)fa[np]=q;
else{
int nq=++tot;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q],fa[np]=fa[q]=nq;
maxlen[nq]=maxlen[p]+1;
while(p&&ch[p][x]==q)ch[p][x]=nq,p=fa[p];
}
}
}
int pa[maxn][25];
void Sort(){///拓扑排序 得到每个集合里的串出现次数
for(int i=1;i<=tot;i++)a[i]=0;
for(int i=1;i<=tot;i++)a[maxlen[i]]++;
for(int i=1;i<=tot;i++)a[i]+=a[i-1];
for(int i=1;i<=tot;i++)b[a[maxlen[i]]--]=i;
for(int i=tot;i;i--)sz[fa[b[i]]]+=sz[b[i]];
for(int i=tot;i;i--){
int k=b[i];
pa[k][0]=fa[k];
rt[fa[k]]=merger(rt[fa[k]],rt[k],1,n);
}
for(int i=1;i<=20;i++){
for(int j=1;j<=tot;j++){
int v=pa[j][i-1];
pa[j][i]=pa[v][i-1];
}
}
}
int go(int id,int len){
for(int i=20;i>=0;i--){
if(maxlen[pa[id][i]]>=len)id=pa[id][i];
}
return id;
}
int m;
void slove(){
for(int i=1;i<=m;i++){
cin>>my[i].l>>my[i].r>>my[i].k;
my[i].id=i;
}
sort(my+1,my+1+m);
int now=1;
int tail=1;
for(int i=1;i<=n;i++){
int x=s[i]-'a';
now=ch[now][x];
while(tail<=m&&my[tail].r==i){
int len=my[tail].r-my[tail].l+1;
int where=go(now,len);
int aa=query(rt[where],1,n,my[tail].k);
if(aa==-1)ans[my[tail].id]=-1;
else{
ans[my[tail].id]=aa-len+1;
}
tail++;
}
}
for(int i=1;i<=m;i++)cout<<ans[i]<<endl;
}
}S;
int main()
{
std::ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
cin>>n;cin>>S.m;
cin>>s+1;
n=strlen(s+1);S.init();
for(int i=1;i<=n;i++)S.add(s[i]-'a',i);
S.Sort();
S.slove();
}
return 0;
}
HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)的更多相关文章
- 区间第k大问题 权值线段树 hdu 5249
先说下权值线段树的概念吧 权值平均树 就是指区间维护值为这个区间内点出现次数和的线段树 用这个加权线段树 解决第k大问题就很方便了 int query(int l,int r,int rt,int k ...
- HDU 6464 免费送气球 【权值线段树】(广东工业大学第十四届程序设计竞赛)
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6464 免费送气球 Time Limit: 2000/1000 MS (Java/Others) M ...
- 2019年CCPC网络赛 HDU 6703 array【权值线段树】
题目大意:给出一个n个元素的数组A,A中所有元素都是不重复的[1,n].有两种操作:1.将pos位置的元素+1e72.查询不属于[1,r]中的最小的>=k的值.强制在线. 题解因为数组中的值唯一 ...
- R - Weak Pair HDU - 5877 离散化+权值线段树+dfs序 区间种类数
R - Weak Pair HDU - 5877 离散化+权值线段树 这个题目的初步想法,首先用dfs序建一颗树,然后判断对于每一个节点进行遍历,判断他的子节点和他相乘是不是小于等于k, 这么暴力的算 ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- 动态求区间K大值(权值线段树)
我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和 ...
- HDU - 2665 Kth number 主席树/可持久化权值线段树
题意 给一个数列,一些询问,问$[l,r]$中第$K$大的元素是哪一个 题解: 写法很多,主席树是最常用的一种之一 除此之外有:划分树,莫队分块,平衡树等 主席树的定义其实挺模糊, 一般认为就是可持久 ...
- BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- HDU - 5592 ZYB's Premutation (权值线段树)
题意:给出序列前k项中的逆序对数,构造出这个序列. 分析:使用权值线段树来确定序列元素. 逆序对的数量肯定是递增的,从最后一个元素开始逆向统计,则\(a[i] - a[i-1]\)即位置i之前比位置i ...
随机推荐
- Django-缓存问题无法创建表
新启的项目,应用不叫app01,也没有userinfo表: 由于缓存原因不能model里创建表报错: 解决办法: 删除init外的所有文件
- AT3576 Popping Balls
AT3576 Popping Balls 好题!一种以前没怎么见过的思路! %%ywy 以什么方式,什么位置统计本质不同的方案,才能不重不漏是处理所有计数问题的主心骨. 本题难以容斥.难以DP. 所以 ...
- 从JMS到KafKa
从JMS到KafKa JMS (1)JMS概念 JMS(Java Message Service,java消息服务)API是一个消息服务的标准或者说是规范,允许应用程序组件基于JavaEE平台创建.发 ...
- 22.从上往下打印二叉树 Java
题目描述 从上往下打印出二叉树的每个节点,同层节点从左至右打印. 解题思路 就是二叉树的层序遍历.借助一个队列就可以实现.使用两个队列一个存放节点,一个存放值.先将根节点加入到队列中,然后遍历队列中的 ...
- [Javascript]客户端检测
客户端检测是一种行之有效的开发策略.但不到万不得已,就不要使用客户端检测.先设计通用的方案,然后根据浏览器之间的差异和各自的怪癖quirky,再使用特定于浏览器的技术增强该方案. 能力检测 Featu ...
- Nginx之编写HTTP模块
1. 常用数据结构 1.1 ngx_str_t typedef struct { /* * 字符串的有效长度 */ size_t len; /* * 有效字符串的起始地址,该字符串通常并不以'\0'结 ...
- 报错1251 - Client does not support authentication protocol 解决办法
# 1.容器中登录mysql,查看mysql的版本 status; # 2,进行授权远程连接(注意mysql 8.0跟之前的授权方式不同) GRANT ALL ON *.* TO 'root'@'%' ...
- Eureka参数配置项详解
Eureka涉及到的参数配置项数量众多,它的很多功能都是通过参数配置来实现的,了解这些参数的含义有助于我们更好的应用Eureka的各种功能,下面对Eureka的配置项做具体介绍,供大家参考. Eure ...
- LC 869. Reordered Power of 2
Starting with a positive integer N, we reorder the digits in any order (including the original order ...
- 视图解析器InternalResourceViewResolver
ModelAndView对象中即可以封装真实视图路径名,也可以封装视图路径的逻辑名,springmvc.xml 代码如下: <!-- 视图解析器(框架) --> <bean clas ...