把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

SP7258 SUBLEX - Lexicographical Substring Search

题面传送门
实际上是一种类似于分治的思想求第\(k\)小子串。
首先构造好SAM。
用拓扑排序预处理出每个节点走下去会碰到多少个子串。
然后对于当前的第\(k\)大子串,我们从小往大枚举,然后看看能不能走下去即可。
时间复杂度\(O(Tn)\)
code:

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
#define l(x) x<<1
#define r(x) x<<1|1
#define N 200039
#define ll long long
#define ui unsigned int
using namespace std;
int n,m,k,x,y,z,T;char a[N];
vector<int> h[N];queue<int>q;
struct SAM{
	int fa[N],son[N][26],len[N],cnt=1,last=1,p,cur,pus,now,g[N],b[N],i,in[N];ll siz[N];
	I void insert(int x){
		p=last,now=last=++cnt;len[now]=len[p]+1;
		while(p&&!son[p][x]) son[p][x]=now,p=fa[p];
		if(!p) return (void)(fa[now]=1);
		cur=son[p][x];if(len[cur]==len[p]+1) fa[now]=cur;
		else{
			fa[pus=++cnt]=fa[cur];len[pus]=len[p]+1;memcpy(son[pus],son[cur],sizeof(son[pus]));fa[now]=fa[cur]=pus;
			while(p&&son[p][x]==cur) son[p][x]=pus,p=fa[p];
		} 
	}
	I void calc(){
		for(i=1;i<=cnt;i++){siz[i]=1;
			for(int j=0;j<=25;j++)son[i][j]&&(h[son[i][j]].push_back(i),in[i]++);
		}
		for(i=1;i<=cnt;i++) if(!in[i]) q.push(i);
		while(!q.empty()){
			now=q.front();q.pop();
			for(i=0;i<h[now].size();i++)pus=h[now][i],siz[pus]+=siz[now],in[pus]--,!in[pus]&&(q.push(pus),0);
		}
	} 
	I void dfs(int x,int w){
		if(w<=1) return;w--;//printf("%d %d\n",x,w);
		for(int i=0;i<=25;i++) {
			if(!son[x][i]) continue;
			if(w<=siz[son[x][i]]){putchar(i+'a');dfs(son[x][i],w);return;}
			w-=siz[son[x][i]];
		}
	}
}s;
int main(){
	freopen("1.in","r",stdin);
	register int i;
	scanf("%s",a+1);n=strlen(a+1);for(i=1;i<=n;i++) s.insert(a[i]-'a');s.calc();
	scanf("%d",&T);while(T--) scanf("%d",&x),s.dfs(1,x+1),putchar('\n');
}
posted @ 2021-03-26 20:02  275307894a  阅读(44)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end