[SCOI2012] 喵星球上的点名
题目链接
听说还可以用AC自动机做,字符集比较大的话,用map就可以了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int ha[50005],res[100005],ans[100005];
int s[500005],id[500005],tot,f[100005],l[100005],u[500005],o[100005];
int rk[20][500005],r[500005],sa[500005],h[500005],w,p[25];
int L[100005],R[100005];
int st[20][500005];
int n,m;
const int tr=10005;
struct t1
{
int v,id;
}t[500005];
struct q1
{
int l,r,id,t;
}q[100005];
bool cmp1(t1 a,t1 b)
{
return a.v<b.v;
}
bool cmp2(int a,int b)
{
if(rk[w-1][a]!=rk[w-1][b])
{
return rk[w-1][a]<rk[w-1][b];
}
return rk[w-1][min(a+p[w-1],500001)]<rk[w-1][min(b+p[w-1],500001)];
}
void pre()
{
for(int i=1;i<=tot;i++)
{
st[0][i]=h[i];
}
for(int i=1;i<=18;i++)
{
for(int j=1;(j+(1<<i)-1)<=tot;j++)
{
st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
}
}
int getl(int x,int f)
{
for(int i=18;i>=0;i--)
{
if((x-(1<<i)+1)>=1&&st[i][x-(1<<i)+1]>=f)
{
x=x-(1<<i);
}
}
return x+1;
}
int getr(int x,int f)
{
x++;
for(int i=18;i>=0;i--)
{
if((x+(1<<i)-1)<=tot&&st[i][x]>=f)
{
x=x+(1<<i);
}
}
return x-1;
}
void SA()
{
p[0]=1;
for(int i=1;i<=20;i++)
{
p[i]=p[i-1]*2;
}
for(int i=1;i<=tot;i++)
{
t[i].id=i;
t[i].v=s[i];
sa[i]=i;
}
sort(t+1,t+tot+1,cmp1);
t[0].v=tr;
int cnt=0;
for(int i=1;i<=tot;i++)
{
if(t[i].v!=t[i-1].v)
{
cnt++;
}
rk[0][t[i].id]=cnt;
}
for(int i=1;i<=19;i++)
{
w=i;
sort(sa+1,sa+tot+1,cmp2);
cnt=0;
for(int j=1;j<=tot;j++)
{
if(rk[w-1][sa[j]]!=rk[w-1][sa[j-1]]||rk[w-1][min(sa[j]+p[w-1],500001)]!=rk[w-1][min(sa[j-1]+p[w-1],500001)])
{
cnt++;
}
rk[w][sa[j]]=cnt;
}
}
for(int i=1;i<=tot;i++)
{
u[i]=id[sa[i]];
r[i]=rk[19][i];
}
for(int i=1;i<=m;i++)
{
o[i]=r[f[i]];
}
int k=0;
for(int i=1;i<=tot;i++)
{
if(r[i]==1)
{
h[r[i]]=0;
k=0;
continue;
}
while(i+k<=tot&&sa[r[i]-1]+k<=tot&&s[i+k]==s[sa[r[i]-1]+k])
{
k++;
}
h[r[i]]=k;
if(k) k--;
}
pre();
}
void del(int j,int i)
{
if(u[j]==0)
{
return;
}
ha[u[j]]--;
ans[q[i].id]-=(ha[u[j]]==0);
res[u[j]]-=((m-i+1)*(ha[u[j]]==0));
}
void add(int j,int i)
{
if(u[j]==0)
{
return;
}
ha[u[j]]++;
ans[q[i].id]+=(ha[u[j]]==1);
res[u[j]]+=((m-i+1)*(ha[u[j]]==1));
}
bool cmp(q1 a,q1 b)
{
if(a.t!=b.t)
{
return a.t<b.t;
}
return a.r<b.r;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int cnt=read1();
for(int j=1;j<=cnt;j++)
{
tot++;
s[tot]=read1();
id[tot]=i;
}
tot++;
s[tot]=tr;
cnt=read1();
for(int j=1;j<=cnt;j++)
{
tot++;
s[tot]=read1();
id[tot]=i;
}
tot++;
s[tot]=tr;
}
for(int i=1;i<=m;i++)
{
f[i]=tot+1;
l[i]=read1();
for(int j=1;j<=l[i];j++)
{
tot++;
s[tot]=read1();
}
tot++;
s[tot]=tr;
}
SA();
/*
for(int i=1;i<=tot;i++)
{
cout<<i<<' ';
for(int j=sa[i];j<=tot;j++)
{
cout<<s[j]<<' ';
}
cout<<endl;
}
*/
/*
for(int i=1;i<=tot;i++)
{
cout.width(3);
cout<<s[i];
}
cout<<endl;
for(int i=1;i<=tot;i++)
{
cout.width(3);
cout<<i;
}
cout<<endl;
*/
int S=tot/sqrt(m);
for(int i=1;i<=m;i++)
{
q[i].l=getl(o[i],l[i])-1;
q[i].r=getr(o[i],l[i]);
q[i].id=i;
q[i].t=q[i].l/S;
}
sort(q+1,q+m+1,cmp);
int L=1,R=0;
q[0].id=0;
for(int i=1;i<=m;i++)
{
ans[q[i].id]=ans[q[i-1].id];
while(L>q[i].l)
{
L--;
add(L,i);
}
while(R<q[i].r)
{
R++;
add(R,i);
}
while(L<q[i].l)
{
del(L,i);
L++;
}
while(R>q[i].r)
{
del(R,i);
R--;
}
}
for(int i=1;i<=m;i++)
{
printf("%d\n",ans[i]);
}
for(int i=1;i<n;i++)
{
printf("%d ",res[i]);
}
printf("%d\n",res[n]);
return 0;
}