您的位置:首页 > 其它

bzoj2754 [SCOI2012]喵星球上的点名

2017-03-15 16:59 302 查看

传送门

脑残错误调了将近一小时……这人没救了

……

其实跟bzoj3881差不多,建出AC自动机之后跑树链的并即可。因为只要出现姓或名就算一次,因此要把两次匹配得到的所有点一起做树链的并。

/**************************************************************
Problem: 2754
User: hzoier
Language: C++
Result: Accepted
Time:1048 ms
Memory:24460 kb
****************************************************************/
#include<cstdio>
#include<cstring>
#include<stdint.h>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
const int maxn=200010;
int insert(const int*,int);
void getfail();
void bfs();
int LCA(int,int);
void match(const vector<int>&,int);
bool cmp(int,int);
map<int,int>ch[maxn];
int f[maxn],q[maxn],val[maxn],d[maxn],cnt=0;
int dfn[maxn],size[maxn],son[maxn],top[maxn],sum[maxn]={0},a[maxn];
vector<int>str1[maxn],str2[maxn];
int n,m,s[maxn],len1[maxn],len2[maxn],iter[maxn],ans[maxn];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&len1[i]);
for(int j=0;j<len1[i];j++)scanf("%d",&s[j]);
str1[i]=vector<int>(s,s+len1[i]);
scanf("%d",&len2[i]);
for(int j=0;j<len2[i];j++)scanf("%d",&s[j]);
str2[i]=vector<int>(s,s+len2[i]);
}
for(int i=1,len;i<=m;i++){
scanf("%d",&len);
for(int j=0;j<len;j++)scanf("%d",&s[j]);
iter[i]=insert(s,len);
}
getfail();
bfs();
for(int i=1;i<=n;i++){
a[0]=0;
match(str1[i],len1[i]);
match(str2[i],len2[i]);
sort(a+1,a+a[0]+1,cmp);
sum[a[1]]++;
ans[i]+=val[a[1]];
for(int j=2,x;j<=a[0];j++){
sum[a[j]]++;
ans[i]+=val[a[j]];
x=LCA(a[j],a[j-1]);
sum[x]--;
ans[i]-=val[x];
}
}
for(int i=cnt;i;i--)sum[f[q[i]]]+=sum[q[i]];
for(int i=1;i<=m;i++)printf("%d\n",sum[iter[i]]);
for(int i=1;i<=n;i++){
if(i>1)printf(" ");
printf("%d",ans[i]);
}
return 0;
}
int insert(const int *a,int n){
int x=0;
for(int i=0;i<n;i++){
if(!ch[x].count(a[i]))ch[x][a[i]]=++cnt;
x=ch[x][a[i]];
}
val[x]++;
return x;
}
void getfail(){
int x,head=1,tail=1;
for(map<int,int>::iterator it=ch[x].begin();it!=ch[x].end();it++)q[tail++]=it->second;
d[0]=1;
while(head!=tail){
x=q[head++];
d[x]=d[f[x]]+1;
val[x]+=val[f[x]];
for(map<int,int>::iterator it=ch[x].begin();it!=ch[x].end();it++){
int y=f[x];
while(y&&!ch[y].count(it->first))y=f[y];
f[it->second]=(ch[y].count(it->first)?ch[y][it->first]:0);
q[tail++]=it->second;
}
}
}
void bfs(){
fill(son,son+cnt+1,cnt+1);
for(int i=cnt,x;i;i--){
x=q[i];
dfn[x]=size[f[x]];
size[x]++;
size[f[x]]+=size[x];
if(size[x]>size[son[f[x]]])son[f[x]]=x;
}
for(int i=1,x;i<=cnt;i++){
x=q[i];
dfn[x]+=dfn[f[x]]+1;
if(x==son[f[x]])top[x]=top[f[x]];
else top[x]=x;
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]])swap(x,y);
x=f[top[x]];
}
return d[x]<d[y]?x:y;
}
void match(const vector<int>&str,int n){
int x=0;
for(int i=0;i<n;i++){
while(x&&!ch[x].count(str[i]))x=f[x];
if(ch[x].count(str[i]))x=ch[x][str[i]];
a[++a[0]]=x;
}
}
bool cmp(int x,int y){return dfn[x]<dfn[y];}
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: