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

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

试题描述

a180285幸运地被选做了地球到喵星球的留学生。他发现喵星人在上课前的点名现象非常有趣。   假设课堂上有N个喵星人,每个喵星人的名字由姓和名构成。喵星球上的老师会选择M个串来点名,每次读出一个串的时候,如果这个串是一个喵星人的姓或名的子串,那么这个喵星人就必须答到。 然而,由于喵星人的字码过于古怪,以至于不能用ASCII码来表示。为了方便描述,a180285决定用数串来表示喵星人的名字。
现在你能帮助a180285统计每次点名的时候有多少喵星人答到,以及M次点名结束后每个喵星人答到多少次吗?  

输入

现在定义喵星球上的字符串给定方法:
先给出一个正整数L,表示字符串的长度,接下来L个整数表示字符串的每个字符。
输入的第一行是两个整数N和M。
接下来有N行,每行包含第i 个喵星人的姓和名两个串。姓和名都是标准的喵星球上的字符串。
接下来有M行,每行包含一个喵星球上的字符串,表示老师点名的串。

输出

对于每个老师点名的串输出有多少个喵星人应该答到。
然后在最后一行输出每个喵星人被点到多少次。

输入示例

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

输出示例

2
1
0
1 2

数据规模及约定

对于30%的数据,保证: 
1<=N,M<=1000,喵星人的名字总长不超过4000,点名串的总长不超过2000。
对于100%的数据,保证:
1<=N<=20000,1<=M<=50000,喵星人的名字总长和点名串的总长分别不超过100000,保证喵星人的字符串中作为字符存在的数不超过10000。

题解

求后缀数组,对于每一次点名,点到的对应了一个区间,对于第一问就是问区间中有多少个不同的数,用个主席树就好了;对于第二问不会做,暴力骗过。。。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}

#define maxn 300010
#define maxN 20010
#define maxM 50010
#define maxlog 19
#define maxnode 6000010

int n, m, Str[maxn], tag[maxn], lst[maxN], pre[maxn], st[maxM], Len[maxM], len;

int rank[maxn], height[maxn], sa[maxn], Ws[maxn];
bool cmp(int* a, int p1, int p2, int l) {
	if(p1 + l > len && p2 + l > len) return a[p1] == a[p2];
	if(p1 + l > len || p2 + l > len) return 0;
	return a[p1] == a[p2] && a[p1+l] == a[p2+l];
}
void ssort() {
	int *x = rank, *y = height;
	int m = 0;
	for(int i = 1; i <= len; i++) Ws[x[i] = Str[i]]++, m = max(x[i], m);
	for(int i = 1; i <= m; i++) Ws[i] += Ws[i-1];
	for(int i = len; i; i--) sa[Ws[x[i]]--] = i;
	for(int j = 1, pos = 0; pos < len; j <<= 1, m = pos) {
		pos = 0;
		for(int i = len - j + 1; i <= len; i++) y[++pos] = i;
		for(int i = 1; i <= len; i++) if(sa[i] > j) y[++pos] = sa[i] - j;
		for(int i = 1; i <= m; i++) Ws[i] = 0;
		for(int i = 1; i <= len; i++) Ws[x[i]]++;
		for(int i = 1; i <= m; i++) Ws[i] += Ws[i-1];
		for(int i = len; i; i--) sa[Ws[x[y[i]]]--] = y[i];
		swap(x, y); pos = 1; x[sa[1]] = 1;
		for(int i = 2; i <= len; i++) x[sa[i]] = cmp(y, sa[i], sa[i-1], j) ? pos : ++pos;
	}
	return ;
}
void calch() {
	for(int i = 1; i <= len; i++) rank[sa[i]] = i;
	for(int i = 1, j, k = 0; i <= len; height[rank[i++]] = k)
		for(k ? k-- : 0, j = sa[rank[i]-1]; Str[i+k] == Str[j+k]; k++);
	return ;
}

int Log[maxn], mnh[maxlog][maxn];
void rmq_init() {
	Log[1] = 0;
	for(int i = 2; i <= len; i++) Log[i] = Log[i>>1] + 1;
	for(int i = 1; i <= len; i++) mnh[0][i] = height[i];
	for(int j = 1; (1 << j) <= len; j++)
		for(int i = 1; i + (1 << j) - 1 <= len; i++)
			mnh[j][i] = min(mnh[j-1][i], mnh[j-1][i+(1<<j-1)]);
	return ;
}
int query(int l, int r) {
	l++;
	if(l > r) return len - sa[r] + 1;
	int t = Log[r-l+1];
	return min(mnh[t][l], mnh[t][r-(1<<t)+1]);
}

int ToT, rt[maxn], sumv[maxnode], lc[maxnode], rc[maxnode];
void update(int& y, int x, int l, int r, int p) {
	sumv[y = ++ToT] = sumv[x] + 1;
	if(l == r) return ;
	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
	if(p <= mid) update(lc[y], lc[x], l, mid, p);
	else update(rc[y], rc[x], mid + 1, r, p);
	return ;
}
int que(int o, int l, int r, int up) {
	if(r <= up) return sumv[o];
	int mid = l + r >> 1, ans = que(lc[o], l, mid, up);
	if(up > mid) ans += que(rc[o], mid + 1, r, up);
	return ans;
}
int ask(int l, int r) {
	return que(rt[r], 0, len, l - 1) - que(rt[l-1], 0, len, l - 1);
}

int vis[maxM], hhh[maxN];

int main() {
	n = read(); m = read();
	for(int i = 1; i <= n; i++) {
		int L = read();
		while(L--) Str[++len] = read(), tag[len] = i;
		Str[++len] = 10001;
		L = read();
		while(L--) Str[++len] = read(), tag[len] = i;
		Str[++len] = 10001;
	}
	for(int i = 1; i <= m; i++) {
		int L = read();
		st[i] = len + 1; Len[i] = L;
		while(L--) Str[++len] = read();
		Str[++len] = 10001;
	}
	
	ssort();
	calch();
	rmq_init();
	/*for(int i = 1; i <= len; i++) printf("%d%c", Str[i], i < len ? ' ' : '\n');
	for(int i = 1; i <= len; i++) printf("%d%c", sa[i], i < len ? ' ' : '\n');
	for(int i = 1; i <= len; i++) printf("%d%c", tag[sa[i]], i < len ? ' ' : '\n');
	for(int i = 1; i <= len; i++) printf("%d%c", height[i], i < len ? ' ' : '\n'); // */
	for(int i = 1; i <= len; i++) pre[i] = lst[tag[sa[i]]], lst[tag[sa[i]]] = i;
	for(int i = 1; i <= len; i++) update(rt[i], rt[i-1], 0, len, pre[i]);
	for(int i = 1; i <= m; i++) {
		int now = rank[st[i]], l = 1, r = now, L, R;
		while(l < r) {
			int mid = l + r >> 1;
			if(query(mid, now) < Len[i]) l = mid + 1; else r = mid;
		}
		L = l;
		l = now; r = len + 1;
		while(r - l > 1) {
			int mid = l + r >> 1;
			if(query(now, mid) < Len[i]) r = mid; else l = mid;
		}
		R = l;
//		printf("%d [%d, %d]\n", now, L, R);
		printf("%d\n", ask(L, R) - 1);
		for(int j = L; j <= R; j++) if(tag[sa[j]] && vis[tag[sa[j]]] != i) vis[tag[sa[j]]] = i, hhh[tag[sa[j]]]++;
	}
	
	for(int i = 1; i <= n; i++) printf("%d%c", hhh[i], i < n ? ' ' : '\n');
	
	return 0;
}

真 TM 调死我了 = =

posted @ 2017-03-30 08:08  xjr01  阅读(183)  评论(0编辑  收藏  举报