1. 程式人生 > >2018.12.15【HDU4622】Reincarnation(字尾自動機SAM)

2018.12.15【HDU4622】Reincarnation(字尾自動機SAM)

傳送門


解析:

SAM基礎操作。

解析:

其實不管其他的單獨看字尾連結,即 f a fa 指標或 f a i l

fail 指標的話,其實這個 f a i l fail 就是 K
M P KMP
裡面的 n x t nxt 陣列,所以新增一個字元後新的子串有多少個,直接用自己的 l
e n len
去減去父親的 l e n len 就可以了。


程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

namespace IO{
	inline int getint(){
		re int num;
		re char c;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	
	inline void outint(int a){
		static char ch[23];
		if(a==0)pc('0');
		while(a)ch[++ch[0]]=a-a/10*10,a/=10;
		while(ch[0])pc(ch[ch[0]--]^48);
	}
}
using namespace IO;

typedef struct SAM_node *point;
struct SAM_node{
	int len;
	point fa,son[26];
	SAM_node():fa(NULL),len(0){memset(son,0,sizeof son);}
	inline point clear(int l=0){
		fa=NULL;
		len=l;
		memset(son,0,sizeof son);
		return this;
	}
};

cs int N=2003;
struct SAM{
	SAM_node nd[N<<1];
	point now,last;
	int strnum;
	SAM():now(nd),last(nd),strnum(0){}
	inline void clear(){
		for(;now>nd;--now)now->clear();
		now=last=nd->clear();
		strnum=0;
	}
	
	inline void push_back(char c){
		c-='a';
		point cur=++now;
		cur->len=last->len+1;
		point p=last;
		for(;p&&!p->son[c];p=p->fa)p->son[c]=cur;
		if(!p)cur->fa=nd;
		else if(p->son[c]->len==p->len+1)cur->fa=p->son[c];
		else {
			point clone=++now,q=p->son[c];
			*clone=*q;
			clone->len=p->len+1;
			q->fa=cur->fa=clone;
			for(;p&&p->son[c]==q;p=p->fa)p->son[c]=clone;
		}
		last=cur;
		strnum+=cur->len-cur->fa->len;
	}
}sam;

int T,q;
char s[N];int len;
int ans[N][N];
signed main(){
	T=getint();
	while(T--){
		scanf("%s",s+1);len=strlen(s+1);
		for(int re i=1;i<=len;++i){
			sam.clear();
			for(int re j=i;j<=len;++j){
				sam.push_back(s[j]);
				ans[i][j]=sam.strnum;
			}
		}
		q=getint();
		while(q--){
			int x=getint(),y=getint();
			outint(ans[x][y]);pc('\n');
		}
	}
	return 0;
}