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[];int id;
node(){memset(c,,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[]=x;
p[]=y;
pre[x]=;
for (int l=,r=,u=q[];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[],l,fa;}s[maxn*];
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+;
for (;t!=-&&!s[t].ch[x];t=s[t].fa) s[t].ch[x]=p;
if (t==-) s[p].fa=;
else if (s[t].l+==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+;
s[p].fa=s[q].fa=r;
for (;t!=-&&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*];
q[]=root;
root->id=;
s[].fa=-;
for (int l=,r=;l<=r;l++) {
node *u=q[l];
for (int i=;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=;i<=n;i++) scanf("%d",a+i);
for (int i=;i<=n;i++) a[i]++;
root=new node;
for (int i=;i<n;i++) {
int x,y;
scanf("%d%d",&x,&y);
e[x].pb(y);e[y].pb(x);
}
for (int i=;i<=n;i++) if (e[i].size()==) bfs(i,root->c[a[i]]);
build();
printf("%lld\n",ans);
return ;
}
BZOJ 3926: [Zjoi20150]诸神眷顾的幻想乡(后缀自动机)
上一篇:office2016与visio2016不能“并存”的问题分析


下一篇:jQuery validata插件实现(每周一插件系列)