HDU 4622 后缀自动机
给出一个字符串,每次询问一个区间[l,r]中有多少个不同的字串。
对于每个区间建立后缀自动机,
对每个节点i,设其父节点为j,该节点表示的字串个数为 (i->ml)-(j->ml) 。
考虑到询问较多,而自动机默认支持在最后增加节点,
对询问区间离线处理,对每个左区间建立后缀自动机。
每次询问O(n)扫描自动机统计即可。
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int MAXN = 2010; struct sanode{ sanode* ch[26]; sanode* f; int ml; }; sanode pool[2*MAXN]; sanode *tail,*init; int tot,all; void add(int c,int len){ sanode *p = tail,*np = &pool[++tot]; np->ml = len; for (;p&&!p->ch[c];p=p->f) p->ch[c]=np; tail=np; if (!p) np->f = init; else if (p->ch[c]->ml==p->ml+1) np->f=p->ch[c]; else{ sanode *q = p->ch[c],*r=&pool[++tot]; *r=*q; r->ml=p->ml+1; q->f=np->f=r; for (;p&&p->ch[c]==q;p=p->f) p->ch[c]=r; } } char s[MAXN]; int T,N; int ans[10010]; struct node{ int l,r; int index; node(int l,int r,int index):l(l),r(r),index(index){} bool operator < (node b) const{ if (l!=b.l) return l<b.l; return r<b.r; } }; vector <node> v; int nl,nr; int main(){ // freopen("in.txt","r",stdin); scanf("%d",&T); while(T--){ scanf("%s",s); scanf("%d",&N); v.clear(); for (int i=1;i<=N;i++){ scanf("%d%d",&nl,&nr); nl--; nr--; v.push_back(node(nl,nr,i)); } sort(v.begin(),v.end()); nl=nr=-1; for (vector<node>::iterator k=v.begin();k!=v.end();k++){ if (k->l!=nl){ memset(pool,0,sizeof(pool)); init=tail=&pool[0]; tot=0; nl=k->l; nr=nl; all=0; } for (nr;nr<=k->r;nr++) add(s[nr]-'a',++all); ans[k->index]=0; for (int i=1;i<=tot;i++) ans[k->index]+=(pool[i].ml-pool[i].f->ml); } for (int i=1;i<=N;i++) printf("%d\n",ans[i]); } }