【字典树】洛谷 P2922 [USACO08DEC]Secret Message G

题链

维护两个数组v1[],v2[],v1[]用于标记,v2[]用于记录v1的后缀和,对于一个询问,如果在字典树上向下查找直到查找不到时,此时答案就是访问到的v1[]的和,如果查找完了,也就是说字典树上还有比询问更长的串,则答案也是访问到的v1[]的和,但是得加上此时的后缀和v2[],因为当前v2[]包含v1[],所以还得减去v1[];

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ll long long
#define ULL unsigned long long
#define Pair pair<LL,LL>
#define ls rt<<1
#define rs rt<<1|1
#define Pi acos(-1.0)
#define eps 1e-6
#define DBINF 1e100
#define mod 998244353
#define MAXN 1e18
#define MS 150000

int n,m;
int p[500009][3];
int v1[500009];
int v2[500009];
int step;

void insert(int len){
	int cc = 0;
	for(int i=1;i<=len;i++){
		int x;
		cin >> x;
		if(!p[cc][x]) p[cc][x] = ++step;
		cc = p[cc][x];
		v2[cc]++;
	}
	v1[cc]++;
}

int find(int len){
	int cc = 0;
	int ans = 0;
	int flag = 0;
	for(int i=1;i<=len;i++){
		int x;
		cin >> x;
		if(!p[cc][x]){
			flag = 1;
		}
		if(flag) continue;
		cc = p[cc][x];
		ans += v1[cc];
	}
	if(flag){
		return ans;
	} 
	ans += v2[cc];
	ans -= v1[cc];
	return ans;
}

int main() {
	ios::sync_with_stdio(false);
	cin >> n >> m;
	for(int i=1;i<=n;i++){
		int len;
		cin >> len;
		insert(len);
	}
	while(m--){
		int len;
		cin >> len;
		cout << find(len) << "\n"; 
	}
	
	return 0;
}
posted @ 2021-05-14 20:20  棉被sunlie  阅读(69)  评论(0)    收藏  举报