[trie树]Master of Both 2022年ICPC杭州站K

文章讨论了一个关于字符串处理的问题,给定一个字符串序列和多个字母顺序的询问,需要计算在不同字母顺序下序列的逆序对数量。解决方案涉及到使用Trie树来构建字符串并更新一个二维数组rel,该数组记录了由特定字符大小关系决定的字符串对数。在每次询问时,根据新的字母顺序更新逆序对计数并输出结果。
摘要由CSDN通过智能技术生成

Professor Hui-Bot is the master of string theory and advanced data structures, so he came up with an interesting problem. Given a sequence of nn strings consisting of only lowercase English letters, how many inversions are there in this sequence when the strings are compared by lexicographical order?

As the most extraordinary student of Hui-Bot, Putata and Budada mastered superb string theory and advanced data structure skills respectively, and they solved this problem together with ease. However, there are qq different parallel universes, where the characters in the alphabet are not appearing in the original order.

Formally, the alphabet in each universe is a string, which is a permutation of the 2626 lowercase English letter, denoting the order each character appears.

A string aa is lexicographically smaller than a string bb if and only if one of the following holds:

  • aa is a prefix of bb, but a≠ba≠b;
  • in the first position where aa and bb differ, the string aa has a letter that appears earlier in the alphabet than the corresponding letter in bb.

The number of inversions in a sequence aa of length nn is the number of ordered pairs (i,j)(i,j) such that 1≤i<j≤n1≤i<j≤n, aj<aiaj<ai.

Please help Putata and Budada in each universe to solve the problem.

Input

The first line of the input contains two integers n,qn,q (1≤n≤5×1051≤n≤5×105, 1≤q≤5×1041≤q≤5×104), denoting the length of the sequence.

For the following nn lines, the ii-th line contains a string sisi (1≤|si|≤1061≤|si|≤106). It is guaranteed that the string consists of only lowercase English letters, and ∑i=1n|si|≤106∑i=1n|si|≤106.

For the following qq lines, each line contains a string tt, denoting the alphabet in one universe. It is guaranteed that tt is a permutation of 2626 lowercase English letters.

Output

Output qq lines, denoting the answer in qq universes.

Example

input

5 3
aac
oiputata
aaa
suikabudada
aba
abcdefghijklmnopqrstuvwxyz
qwertyuiopasdfghjklzxcvbnm
aquickbrownfxjmpsvethlzydg

output

4
3
4

题意: 给出n个字符串,以及q次询问,每次询问给出一个字母之间的大小顺序,问在该顺序下这n个字符串的逆序对个数。

分析: 两字符串比较大小需要看第一个不同的字符,对于任意两字符串可以找到它们第一个不同的字符,设它们为x和y,那么可以用一个二维数组记录一下,令rel[x][y]++,这里的rel[i][j]就表示由i和j大小决定的字符串的对数,如果在某个询问中i的字典序大于j的字典序,因为在记录的时候又是按照i所在字符串出现在j所在字符串之前,那么逆序对个数就可以加上rel[i][j],最终扫描一遍rel数组就能够得到答案。最后注意因为字典序判断的时候还可能出现abc和abcd的情况,所以每个字符串最后都需要添加一个比较小的字符。

rel数组的更新需要用到trie树,一遍建树一遍更新即可,能决定两字符串大小的字符只会出现在trie树上的分叉节点上,所以可以根据这个特点来更新rel数组。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
using namespace std;

char s[1000005];
int idx, son[2000005][30];
long long cnt[2000005];
long long rel[30][30]; 

void insert(){
	int now = 0;
	for(int i = 1; s[i]; i++){
		int t = s[i]-'a'+1;
		if(!son[now][t]) son[now][t] = ++idx;
		for(int j = 0; j <= 26; j++){
			if(j == t) continue;
			rel[j][t] += cnt[son[now][j]];
		}
		now = son[now][t];
		cnt[now]++;
	}
}

signed main(){
	int n, q;
	scanf("%d%d", &n, &q);
	for(int i = 1; i <= n; i++){
		scanf("%s", s+1);
		int len = strlen(s+1);
		s[len+1] = 'a'-1;
		s[len+2] = '\0';
		insert();
	} 
	char s[30];
	int mp[30];
	mp[0] = 0;
	for(int i = 1; i <= q; i++){
		scanf("%s", s+1);
		int len = strlen(s+1);
		for(int j = 1; j <= len; j++)
			mp[s[j]-'a'+1] = j;
		long long ans = 0;
		for(int j = 0; j <= 26; j++)
			for(int k = 0; k <= 26; k++){
				if(mp[j] > mp[k]) 
					ans += rel[j][k];
			}
		printf("%lld\n", ans);
	}
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值