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

luogu P5353 树上后缀排序

题面传送门
这个东西其实和序列上sa差不多,树上倍增数组预处理后同样倍增即可。
但是有一个问题就是序列上的sa由于各后缀长度不一,所以不会出现相等的情况,而树上则会出现。
由于题目中给出的比较方法是依据父节点的,而题目中又保证父节点在子节点前面,所以从小到大处理即可。
时间复杂度\(O(nlogn)\)
code:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
#define mod 998244353
#define base 7
#define beg(x) int cur=s.h[x]
#define end cur
#define go cur=tmp.z
using namespace std;
int n,m,k,x,y,z,now,sa[500039],rk[500039],w[500039],f[500039],fa[500039][21],d[500039],flag[500039],fl[500039],l,r;
long long g[500039];
char _s;
struct yyy{int to,z;};
struct ljb{
	int head,h[500039];yyy f[500039];
	inline void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}
}s;
inline void dfs(int x,int last){
	fa[x][0]=last;d[x]=d[last]+1;yyy tmp;int i;g[x]=(g[last]*base+w[x])%mod;
	for(i=1;fa[x][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1];
	for(beg(x);end;go)tmp=s.f[cur],dfs(tmp.to,x);
}
struct fsa{int x,y,num;}a[500039],p[500039];
inline bool cmp(int x,int y){return rk[fa[x][0]]==rk[fa[y][0]]?x<y:rk[fa[x][0]]<rk[fa[y][0]];}
int main(){
	freopen("1.in","r",stdin);
	register int i,j;
	scanf("%d",&n);
	for(i=2;i<=n;i++) scanf("%d",&x),s.add(x,i);
	for(i=1;i<=n;i++){
		for(_s=getchar();_s<'a'||_s>'z';_s=getchar());
		w[i]=_s;
	}
	dfs(1,0);
	for(i=1;i<=n;i++) f[w[i]]++;
	for(i=1;i<=128;i++) f[i]+=f[i-1];
	for(i=n;i;i--) rk[i]=f[w[i]];
	for(i=0;(1<<i)<=n;i++){
		for(j=1;j<=n;j++) p[j]=(fsa){rk[j],rk[fa[j][i]],j};
		memset(f,0,sizeof(f));
		for(j=1;j<=n;j++) f[p[j].y]++;
		for(j=1;j<=n;j++) f[j]+=f[j-1];
		for(j=n;j;j--) a[f[p[j].y]--]=p[j];
		memset(f,0,sizeof(f));
		for(j=1;j<=n;j++) f[p[j].x]++;
		for(j=1;j<=n;j++) f[j]+=f[j-1];
		for(j=n;j;j--) p[f[a[j].x]--]=a[j];
		for(j=1;j<=n;j++) rk[p[j].num]=rk[p[j-1].num]+(p[j].x!=p[j-1].x||p[j].y!=p[j-1].y);
	}
	for(i=1;i<=n;i++) f[rk[i]]++;
	for(i=n;i;i--) rk[i]=f[rk[i]]--;
	for(i=1;i<=n;i++) sa[rk[i]]=i;
	for(i=1;i<=n;i++) fl[i]=fl[i-1]+(g[sa[i]]!=g[sa[i-1]]);
	for(i=1;i<=n;i++){
		if(!flag[fl[rk[i]]]){
	        flag[fl[rk[i]]]=1;l=rk[i],r=rk[i];
	    	while(fl[l-1]==fl[l]) l--;while(fl[r+1]==fl[r]) r++;
    		sort(sa+l,sa+r+1,cmp);
    	    for(k=l;k<=r;k++)rk[sa[k]]=k;
        }
	}
	for(i=1;i<=n;i++) printf("%d ",sa[i]);
}
posted @ 2021-02-18 20:15  275307894a  阅读(69)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end