[bzoj2754] [SCOI2012]喵星球上的点名

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('\n');}

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;
}
posted @ 2019-01-18 12:01  Hyscere  阅读(129)  评论(0编辑  收藏  举报