Description
a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。 假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?
Input
现在定义喵星球上的字符串给定方法:
先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数N和M。
下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的
字符串。
接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。
Output
对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。
Sample Input
2 3
6 8 25 0 24 14 8 6 18 0 10 20 24 0
7 14 17 8 7 0 17 0 5 8 25 0 24 0
4 8 25 0 24
4 7 0 17 0
4 17 0 8 25
Sample Output
2
1
0
1 2
Solution
先建出后缀数组,求一发(height)。
然后正解是按字典序用树状数组维护颜色,然后随便搞搞。。
其实这题直接暴力是可以过官方数据的。
暴力向上和向下跳,枚举颜色更新答案就行。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('
');}
const int maxn = 5e5+10;
int N,M,n,s[maxn],col[maxn],st[maxn],len[maxn];
int spx[maxn],spy[maxn],sa[maxn],rk[maxn],height[maxn],sum[maxn];
void get_sa() {
int p=0,m=n+10000,*x=spx,*y=spy;
for(int i=1;i<=n;i++) sum[x[i]=s[i]]++;
for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
for(int i=n;i;i--) sa[sum[x[i]]--]=i;
for(int k=1,tot=0;p<n;tot=0,k<<=1) {
p=0;
for(int i=n-k+1;i<=n;i++) y[++tot]=i;
for(int i=1;i<=n;i++) if(sa[i]>k) y[++tot]=sa[i]-k;
for(int i=1;i<=m;i++) sum[i]=0;
for(int i=1;i<=n;i++) sum[x[y[i]]]++;
for(int i=1;i<=m;i++) sum[i]+=sum[i-1];
for(int i=n;i;i--) sa[sum[x[y[i]]]--]=y[i];
swap(x,y),x[sa[1]]=p=1;
for(int i=2;i<=n;i++)
if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) x[sa[i]]=++p;
else x[sa[i]]=p;
m=p;
}
}
void get_height() {
for(int i=1;i<=n;i++) rk[sa[i]]=i;
int p=0;
for(int i=1;i<=n;i++) {
if(p) p--;
while(s[i+p]==s[sa[rk[i]-1]+p]) p++;
height[rk[i]]=p;
}
}
int t[maxn],res[maxn];
int main() {
read(N),read(M);
for(int i=1;i<=N;i++) {
int k,x;read(k);
while(k--) read(x),s[++n]=x,col[n]=i;
read(k);s[++n]=10000+i+N+M;
while(k--) read(x),s[++n]=x,col[n]=i;
s[++n]=10000+i;
}
for(int i=1;i<=M;i++) {
int k,x;read(k);len[i]=k,st[i]=n+1;
while(k--) read(x),s[++n]=x,col[n]=N+i;
s[++n]=10000+N+i;
}
get_sa(),get_height();
for(int i=1;i<=M;i++) {
int pos=rk[st[i]],p1,p2;
for(p1=pos;p1>1;p1--) if(height[p1]<len[i]) break;
for(p2=pos+1;p2<=n;p2++) if(height[p2]<len[i]) break;p2--;
int ans=0;
for(int p=p1;p<=p2;p++) {
int c=col[sa[p]];
if(c>N) continue;
if(t[c]!=i) t[c]=i,ans++,res[c]++;
}
write(ans);
}
for(int i=1;i<=N;i++) printf("%d ",res[i]);puts("");
return 0;
}