您的位置:首页 > 其它

BZOJ 2754 [SCOI2012]喵星球上的点名

2016-09-27 13:56 525 查看
AC自动机

对每一个询问串建AC自动机,拿每一个名字跑AC自动机,不断在fail指针上统计答案即可。因为字符串总长度有保证,时间复杂度可以近似看成O(LEN)。

刚开始比较SB,每一个trie节点都开了一个next[10000],结果MLE了。实际上每个节点根本用不到这么多,可以改成map。

做fail指针的时候不用从1扫到10000来找子节点,因为子节点并没有那么多,可以把子节点的编号用vector记录下来,要不然应该会T。

#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#include<cstring>
#define N 20005
#define M 50005
#define NUM 10005
#define LEN 1000005
using namespace std;
int in()
{
int r=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')r=r*10+c-'0',c=getchar();
return r;
}
vector<int> name
[2];
vector<int> son[LEN];
int hash[M], ans
, nodecnt=0, cnt[LEN], siz[LEN], vis[LEN];
struct node
{
node *fail;
map<int,node*> next;
int id;
node(){id=0;fail=NULL;}
};
struct ACAutomaton
{
node *root;
void init()
{
root=new node();
root->fail=root;
root->id=++nodecnt;
}
void insert(int len, int id)
{
node *p=root;
for(int k = 1; k <= len; k++)
{
int x=in();
if(p->next[x]==NULL)
{
p->next[x]=new node();
p->next[x]->id=++nodecnt;
son[p->id].push_back(x);
}
p=p->next[x];
}
hash[id]=p->id;
siz[p->id]++;
}
void build()
{
queue<node*> q;
for(int j = 0, jj = son[root->id].size();j < jj; j++)
{
int i=son[root->id][j];
root->next[i]->fail=root;
q.push(root->next[i]);
}
while(!q.empty())
{
node *u=q.front();
q.pop();
for(int j = 0, jj = son[u->id].size(); j < jj; j++)
{
int i=son[u->id][j];
node *v=u->next[i], *t=u->fail;
while(t!=root && !t->next[i])
{
t=t->fail;
}
v->fail=t->next[i]?t->next[i]:root;
q.push(v);
}
}
}
void solve(int x)
{
for(int k = 0; k < 2; k++)
{
node *p=root;
for(int i = 0, ii = name[x][k].size(); i < ii; i++)
{
int c=name[x][k][i];
while(p!=root && !p->next[c])p=p->fail;
if(p->next[c])p=p->next[c];
node *temp=p;
for(;temp!=root;temp=temp->fail)
{
if(vis[temp->id]==x)continue;
vis[temp->id]=x;
ans[x]+=siz[temp->id];
cnt[temp->id]++;
}
}
}
}
}AC;
int main()
{
AC.init();
int n, m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
{
for(int j = 0; j < 2; j++)
{
int k;
scanf("%d",&k);
for(int g = 1; g <= k; g++)
name[i][j].push_back(in());
}
}
for(int i = 1; i <= m; i++)
{
int k=in();
AC.insert(k,i);
}
AC.build();
for(int i = 1; i <= n; i++)
AC.solve(i);
for(int i = 1; i <= m; i++)
printf("%d\n",cnt[hash[i]]);
for(int i = 1; i < n; i++)
printf("%d ",ans[i]);
printf("%d",ans
);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: