CodeForces 128B [ 后缀树 ]

后缀树 后缀树其实是Trie树的改进,一棵后缀树包含了一个或多个字符串的所有后缀。 对于字符串banana,如果要用trie树来表示它所有的后缀,如下图: 然后对所有的【只有单个子节点的节点】进行合并 然后就可得到后缀树 构造一棵后缀trie树的时 阅读详情

虽然是B题,正解是很简单的优先队列,但还是拿来当后缀树模板题敲了一下,O(N)求第K大子串;

这题只求了一个第K大串,但实际上,多个询问应该也是能搞的:

和后缀数组相仿,在后缀树上两端都是非叶子节点的边直接按 边上记录的[L,R]进行枚举遍历,是O(N)复杂度的,在遍历时用一个栈存储串的信息,是可以做到的。

然后就是第K大串可能在叶子节点向上的连边中,这时候因为这条边的一个字符的价值只有1(价值代表单位字符每多一个count增大多少,这里的count代表现在枚举到的串是第几大,价值为这条边底下的叶子节点数),所以可以直接算,或者打个标记之类的,就可以得到啦~

所以:如果询问的第K大串是有重复的(即这个串在所有子串出现了至少两次),那么询问M次,其复杂度是 O(MAX(size*N,M)),size是字符集大小;

如果有单一的存在,复杂度为O(max(Σ(单一串长),原来的复杂度));


总结了这么多,这题的代码如下:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;


#define SIZE 27
struct suffixtree{
        struct node{
        int l,r,point,a[SIZE];
        void init(){
            mem(a,0);
            point=l=0;
            r=-1;
        }
    }T[400011];
    char s[400011];
    int actnode,actride,actline;
    int rest,total,temp,linker,len;
    void builtleaf(int root,int line){
        total++;
        T[total].init();
        T[total].l=len;
        T[total].r=100000001;
        T[root].a[line]=total;
        rest--;
    }
    bool pd_ride(int next){
        temp=T[next].r-T[next].l+1;
        if(actride>=temp){
            actride-=temp;
            actnode=next;
            actline+=temp;
            return true;
        }
        return false;
    }
    void link(int x){
        if(linker>0)T[linker].point=x;
        linker=x;
    }
    void insert(int wait){
        s[++len]=wait;
        rest++;
        linker=0;
        while(rest>0){
            if(actride==0)actline=len;
            if(T[actnode].a[s[actline]]==0){ 
                builtleaf(actnode,s[actline]);
                link(actnode);
            }
            else{
                int next=T[actnode].a[s[actline]];
                if(pd_ride(next))continue;
                if(s[T[next].l+actride]==wait){
                    actride++;
                    link(actnode);
                    break;
                }  
                total++;
                T[total].init();
                T[actnode].a[s[actline]]=total;
                T[total].l=T[next].l;
                T[total].r=T[next].l+actride-1;
                T[next].l+=actride;
                T[total].a[s[T[next].l]]=next;
                link(total);
                builtleaf(total,wait);
            }
            if(actnode==0&&actride>0){
                actride--;
                actline=len-rest+1;
            }
            else actnode=T[actnode].point;
        }
    }
    void clear(){
        total=0;
        len=0;
        T[0].init();
        actnode=actride=actline=0;
    }
    void debug(){
        rep(i,0,total){
            printf("T[%d] (%d %d)\n",i,T[i].l,T[i].r);
        }
    }
}st; 

#define NN 400400
char s[NN];
ll cot[NN];
ll sum;
ll k;
int len;

ll getcot(int x){
    ll temp=0;
    ll bj=1;
    rep(i,0,26){
        if(st.T[x].a[i]){
            bj=0;
            temp+=getcot(st.T[x].a[i]);
        }
    }
    cot[x]=temp+bj;
    return cot[x];
}
ll edr,edx;
int alen=0;
char ans[NN];
void dfs(int x){
    sum+=(ll)(min(st.T[x].r,len)-st.T[x].l+1)*cot[x];
    if(sum>=k){
        edx=x;
        edr=min(ll(st.T[x].r),ll(len));
        while(sum-cot[x]>=k){
            sum-=cot[x];
            edr--;
        }
        //printf("%lld %lld\n",edx,edr);
        //return;
    }
    rep(i,0,26){
        if(st.T[x].a[i]&&sum<k){
            dfs(st.T[x].a[i]);
        }
    }
    if(sum>=k){
        drep(i,min(edr,ll(st.T[x].r)),st.T[x].l){
            ans[alen++]=s[i];
        }
    }
}




main(){
    st.clear();
    scanf("%s",s+1);
    len=strlen(s+1);
    rep(i,1,len)st.insert(s[i]-'a');
    st.insert(26);
    scanf("%lld",&k);
    if(ll(len)*ll(len+1)/2LL<k){
        printf("No such line.\n");
        return 0;
    }
    getcot(0);
    dfs(0);
    ans[alen]=0;
    reverse(ans,ans+alen);
    printf("%s\n",ans);
}



数据结构之后缀树 后缀数组 阅读详情

相关推荐

保姆级教程:用CST 2023一步步复现一个1-8GHz Vivaldi天线(含参数优化与结果分析)

本文提供了一份详细的CST 2023教程,指导读者如何从零开始设计并优化1-8GHz Vivaldi天线。内容涵盖工程设置、参数化建模、仿真加速技巧以及性能优化策略,特别适合需要实现宽带天线设计的工程师和研究人员。通过实战案例,帮助用户掌握Vivaldi天线的核心设计要点和CST高级功能应用。

weixin_30800987的博客 618

课堂反转——数据结构之后缀树

后缀树基本原理及构造函数的实现

Strelitzia7的博客 1388

「转载」vaptcha 等手势验证码图像识别与轨迹提取(思路)

作者:文安哲 从博客重开以后就说要更文章,鸽了蛮久了,赶紧补上一篇嫖嫖各位老公的流量。 最近看群里面大家讨论研究手势验证码比较多,然后我也顺带研究做了一下,给各位老公们分享一下做的过程。 首先,一起来康康手势验证码长啥样! 大概就是长这个样子,需要按照图像中的那条轨迹再图片上滑动,不得不说这类验证码确实体验感拉满,让人很想立马关掉这个网站。 那么言归正传,这类验证码该怎么做识...

AI悦创·编程私教1v1 3597

后缀树(一)定义及构造

后缀树(Suffix tree): :一个具有m个词的字符串S的后缀树T,就是一个包含一个根节点的有向树,该树恰好带有m个叶子,这些叶子被赋予从1到m的标号。每一个内部节点,除了根节点以外,都至少有两个子节点,而且每条边都用$的一个非空子串来标识。出自同一节点的任意两条边的标识不会以相同的词开始。后缀树的关键特征是:对于任何叶子i,从根节点到该叶子所经历的边的所有标识串联起来后恰好拼出S的从i...

)梦想之深邃( 2416

数字后端零基础入门系列 | Innovus零基础LAB学习Day7

数字后端零基础入门系列 | Innovus零基础LAB学习Day7

weixin_37584728的博客 2269

OpenCV教程:超详细的OpenCV入门教程,值得收藏

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,它提供了很多函数,这些函数非常高效地实现了计算机视觉算法(最基本的滤波到高级的物体检测皆有涵盖)。 OpenCV 使用 C/C++ 开发,同时也提供了 Python、Java、MATLAB 等其他语言的接口。 OpenCV 是跨平台的,可以在Windows、Linux、Mac OS、Android、iOS 等操作系统上运行。 OpenCV 的应用领域非常广泛,包括图像拼接、图像降噪、产品质检、..

pythonandaiot的博客 14万+

数据结构与算法面试分享(二十一):后缀树(Suffix Tree)

上述字符串匹配算法(朴素的字符串匹配算法, KMP 算法, Boyer-Moore算法)均是通过对模式(Pattern)字符串进行预处理的方式来加快搜索速度。对 Pattern 进行预处理的最优复杂度为 O(m),其中 m 为 Pattern 字符串的长度。那么,有没有对文本(Text)进行预处理的算法呢?本文即将介绍一种对 Text 进行预处理的字符串匹配算法:后缀树(Suffix Tree)。后缀树的性质存储所有 n(n-1)/2 个后缀需要 O(n) 的空间,n 为的文本(Text)的长度;

之乎者也·的博客 1811

解决RuntimeError: Couldn‘t load custom C++ ops. This can happen if your PyTorch

刚下好yolov8的代码,想测一下能否成果,果然没成功,报错如下简单来说就是torchvision和torch不匹配,就很离谱,我照着版本对应关系pip install的啊,怎么会不匹配建议先看看你的版本我是下图红框这个首先确定自己torch没问题,因为我的3090这个卡目前cuda版本是11.1,这个whl是早就下好的,一般1-2G,有问题重新下就麻烦了然后我pip install了很多次torchvision==0.11.3,都没啥用。想试着改改版本,结果要下其他的torch版本,就更不可能了。

DZY的博客 2247

Suffix Tree (后缀树)、Suffix Array (后缀数组)、LZW树详细解读

以下是 后缀树(Suffix Tree)、后缀数组(Suffix Array) 以及 LZW树 的详细介绍,包括定义、原理、优缺点和应用场景。

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1728

第055篇:陆地观测卫星数据服务平台高级检索方法

检索数据检索到肩膀疼,这谁能信?谁能?

liujinli0712的博客 7823

EV1527、PT2262傻傻分不清?一文讲透常见315/433MHz遥控编码协议区别与选型

本文深度对比了EV1527、PT2262和SC5262三种常见的315/433MHz遥控编码协议,详细解析了它们的技术特点、成本效益和适用场景。EV1527作为低成本方案的首选,特别适合智能家居和简易安防设备;PT2262在稳定性和兼容性上表现优异;而SC5262则在安全性方面具有显著优势。文章还提供了实用的选型框架和工程建议,帮助开发者在不同应用场景中做出最优决策。

weixin_33640562的博客 349

后缀树(Suffix Tree)简介

新建一个z,使st[z]=n,len[z]=inf,再新建一个u,使st[u]=st[v],len[u]=rem-1,tran[now][S[n-rem+1]]=u,tran[u][S[st[v]+rem-1]]=v,tran[u][c]=z。首先如果len[tran[now][S[n-rem+1]]]>rem,就跨越这条出边,直到len[tran[now][S[n-rem+1]]] ≤ rem,因为当前待插入新后缀去掉尾字符就是已插入的隐式后缀,这条边肯定能走通。对应于原串后缀的节点x称为。

wisoredcsdn的博客 1148

25、格式化字符串攻击全解析

本文深入解析了格式化字符串攻击的原理与利用方式,涵盖缓冲区溢出与格式化字符串漏洞的区别,详细介绍了printf函数的工作机制、常见格式化说明符及其安全隐患。文章分析了三类典型编程错误导致的漏洞,并展示了如何通过恶意格式化字符串实现拒绝服务、内存读取和写入攻击。同时,提供了有效的防御措施,包括输入验证、使用安全函数、避免直接使用用户输入作为格式化字符串以及启用编译器安全选项,帮助开发者防范此类高危漏洞。

beer8的博客 83

树:后缀树

在 trie 数据结构中,给定字符串中所有字符串的每个字母表一个接一个地遍历,每个节点代表一个字母表。如果两个或多个单词以相同的子字符串开头,则相同的子字符串由相同的节点链表示。这是一个压缩的 trie,包括字符串的所有后缀。个后缀中的每一个节点一个,没有后缀是另一个后缀的前缀。下面是我们之前用于进行 try 的相同朋友名称列表的后缀树的表示。后缀树的空间使用量远远大于序列集合的实际大小,无论它是线性的。无论哪种方式,都已经发表了开发基于磁盘的后缀树的实际工作,这些后缀树可以扩展到(几)GB/小时。

新华编程特战队 1212

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

【字符串】后缀树(Suffix Tree)

后缀树是压缩字典树,含字符串所有后缀。Ukkonen算法以O(n)时间构建,利用后缀链接与三规则高效扩展,是处理子串搜索、重复子串等难题的利器。

zhangmohan123321的博客 1435

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

[算法系列之二十四]后缀树(Suffix Tree)

之前有篇文章([算法系列之二十]字典树(Trie))我们详细的介绍了字典树。有了这些基础我们就能更好的理解后缀树了。 一 引言 模式匹配问题 给定一个文本text[0…n-1], 和一个模式串 pattern[0…m-1],写一个函数 search(char pattern[], char text[]), 打印出pattern在text中出现的所有位置(n &gt; m)。 这个问题...

SmartSi 1255

【数据结构】后缀树

1、简介后缀树(Suffix tree)是一种数据结构,能快速解决很多关于字符串的问题。后缀树提出的目的是用来支持有效的字符串匹配和查询。一个具有m个词的字符串S的后缀树T,就是一个包含一个根节点的有向树,该树恰好带有m个叶子,这些叶子被赋予从1到m的标号。 每一个内部节点,除了根节点以外,都至少有两个子节点,而且每条边都用$的一个非空子串来标识。出自同一节点的任意两条边的标识不会以相同的词开始。...

qq280929090的专栏 876

后缀树的构造方法-Ukkonen详解

后缀树的构造方法-Ukkonen详解   2010-09-13 21:47:06|  分类: 算法 |  标签:后缀树的构造方法-  ukkonen详解   |字号大中小 订阅   最近在学习后缀树的构造,在网上找了好久发觉国内详解它的构造的文章胜少,在苦苦寻觅了许久,终于发现了一个网友翻译的一篇文章,很好,于是我转帖出来,希望能有更多的人受益,也希望国内多

zhongjie的专栏 2112

数据结构系列——后缀树(附Java实现代码)

后缀树,说的通俗点就是将一个字符串所有的后缀按照前缀树(Trie树,可参考此篇文章)的形式组织成一棵树。本文章介绍了后缀树的应用以及使用如何使用Java实现Ukkonen算法构建后缀树

收拾心灵_描绘未来 6300

后缀树解析

写这篇文章,主要是因为最近有个课题设计,里面用的字符串匹配。 学习后缀树之前,先了解一下Trie这个数据结构 Trie是一种搜索树,可用于存储并查找字符串。Trie每一条边都对应一个字符。在Trie中查找字符串S时,只要按顺序枚举S的各个字符,从Trie的根节点开始选择相应的边走,如果枚举完的同时恰好走到Trie树的叶子节点,说明S存在于Trie中。如果未到达叶子节点,或者枚举中未发现相应

marken 3592

数据结构第29节 后缀树和后缀数组

后缀树和后缀数组都是用于高效处理字符串搜索问题的数据结构,它们特别适合于解决涉及字符串模式匹配、重复子串查找等问题。下面我将结合Java代码解释这两种数据结构的基本概念以及如何构建它们。

hummhumm的专栏 840

知识点 - 后缀树模板

知识点 - 后缀树模板 解决问题类型: 读入一个串,建一颗后缀树 论文: Algorithms on Strings, Trees, and Sequences 定义与代码: O(nlog⁡(k))O(n\log(k))O(nlog(k))建树k是字母表大小。 string s; int n; struct node { int l, r, par, link; map<char,i...

qq_41848675的博客 515

后缀自动机转后缀树模板

终于找到教程了,现在来写一发 题目:Jzoj4072(bzoj3998)弦论 第一问 其实非常好写,连空间都不需要多开一倍,只需要sa数组rank数组和height数组就好了,dfs一次可以求出 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<algori...

dianning8393的博客 234
上一篇: CodeForces 128A Statues [基础DP]
下一篇: CodeForces 128C Games with Rectangle [组合数学+基础DP]
GrassTreeFlower
博客等级 码龄11年 14粉丝 116原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值