虽然是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);
}