BZOJ 3926: [Zjoi20150]诸神眷顾的幻想乡(后缀自动机)
被这道题坑了= =
只与一个空地相连的空地不超过20个
只与一个空地相连的空地不超过20个
因为很重要所以说两遍
就是说儿子节点最多只有20个
把这20个节点作为根遍历一遍所得到的tire所得到的所有不同子串就是答案了
怎么求?
这可是CLJ出的啊
想想她讲过什么
后缀自动机或可持久化后缀数组的经典应用
由于不会打可持久化后缀数组,就打了个自动机
自己对后缀自动机根本不熟,找时间在多做几道题
CODE:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> using namespace std; struct node{ node* c[12];int id; node(){memset(c,0,sizeof(c));} }; #define maxn 101000 vector<int> e[maxn]; #define pb push_back int a[maxn],pre[maxn]; inline void bfs(int x,node *&y){ if (!y) y=new node; static int q[maxn]; static node * p[maxn]; q[1]=x; p[1]=y; pre[x]=0; for (int l=1,r=1,u=q[1];l<=r;u=q[++l]) { for (vector<int>::iterator i=e[u].begin();i!=e[u].end();++i) { if (*i==pre[u]) continue; pre[*i]=u;q[++r]=*i; if (!p[l]->c[a[*i]]) p[l]->c[a[*i]]=new node; p[r]=p[l]->c[a[*i]]; } } } struct snode{int ch[13],l,fa;}s[maxn*50]; typedef long long ll; int cnt;ll ans; inline void add(int x,node* u) { int p=++cnt,t=u->id; u->c[x]->id=p; s[p].l=s[t].l+1; for (;t!=-1&&!s[t].ch[x];t=s[t].fa) s[t].ch[x]=p; if (t==-1) s[p].fa=0; else if (s[t].l+1==s[s[t].ch[x]].l) s[p].fa=s[t].ch[x]; else { int r=++cnt,q=s[t].ch[x]; s[r]=s[q];s[r].l=s[t].l+1; s[p].fa=s[q].fa=r; for (;t!=-1&&s[t].ch[x]==q;t=s[t].fa) s[t].ch[x]=r; } ans+=s[p].l-s[s[p].fa].l; } int c; node *root; inline void build(){ static node *q[maxn*50]; q[1]=root; root->id=0; s[0].fa=-1; for (int l=1,r=1;l<=r;l++) { node *u=q[l]; for (int i=0;i<=c;i++) if (u->c[i]) { add(i,u); q[++r]=u->c[i]; } } } int main(){ int n; scanf("%d%d",&n,&c); for (int i=1;i<=n;i++) scanf("%d",a+i); for (int i=1;i<=n;i++) a[i]++; root=new node; for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); e[x].pb(y);e[y].pb(x); } for (int i=1;i<=n;i++) if (e[i].size()==1) bfs(i,root->c[a[i]]); build(); printf("%lld\n",ans); return 0; }