AFO

[TJOI2015]弦论

重学了一下SAM

终终终终终于差不多知道他的实现原理了qaqaqaq

P3975 [TJOI2015]弦论

先建SAM

对于t=0的每个节点的size都是1,对于t=1的每个节点的size就是子树内叶子的个数

然后维护子树和以后就是一个类似求权值平衡树第k大的感觉

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define LL long long 
using namespace std;
const int M =1000001;

int tag,K,las=1,cnt=1,n,m,k,d[M][26],f[M],len[M],a[M];
LL S[M],sz[M];
char c[M];

struct vv
{
	int pos,len;
} t[M];

void SAM(int k)
{
	int x=++cnt, y=las; len[x]=len[y]+1; sz[x]=1; las=x;
	for(;y && !d[y][k];y=f[y]) d[y][k]=x;
	if(!y){ f[x]=1; return ;}
	int p=d[y][k];
	if(len[p]==len[y]+1) {f[x]=p; return ;}
	int np=++cnt;
	len[np]=len[y]+1;
	f[np]=f[p];
	f[p]=f[x]=np;
	memcpy(d[np],d[p],sizeof(d[p]));
	for(;y && d[y][k]==p;y=f[y]) d[y][k]=np;
}

bool cmp(vv a,vv b)
{
	return a.len>b.len;
}

int main()
{
	//freopen("s1.txt","r",stdin);
	scanf("%s",c+1);
	scanf("%d%d",&tag,&K);
	n=strlen(c+1);
	for(int i=1;i<=n;i++) SAM(c[i]-'a');
	for(int i=1;i<=cnt;i++) 
	{
		t[i].pos=i;
		t[i].len=len[i];
	}
	sort(t+1,t+1+cnt,cmp);	
	for(int i=1;i<=cnt;i++)
	{
		if(tag) sz[f[t[i].pos]]+=sz[t[i].pos];
		else sz[t[i].pos]=1;
	}
	sz[1]=0;
	for(int i=1;i<=cnt;i++)
	{
		S[t[i].pos]=sz[t[i].pos];
		for(int j=0;j<26;j++) S[t[i].pos]+=S[d[t[i].pos][j]];
	}
	if(S[1]<K) { printf("-1"); return 0;}
	int now=1;
	while(1)
	{
		if(K<=sz[now]) break;
		K-=sz[now];
		for(int i=0;i<26;i++) if(d[now][i] && S[d[now][i]]>=K) 
		{
			printf("%c",i+'a');
			now=d[now][i];
			break;
		}
		else K-=S[d[now][i]];
	}
}
posted @ 2019-12-05 20:49  ZUTTER☮  阅读(108)  评论(0编辑  收藏  举报