hdu 5790 Prefix(字典树+主席树)

Problem Description
Alice gets N strings. Now she has Q questions to ask you. For each question, she wanna know how many different prefix strings between Lth and Rth strings. It's so easy right? So solve it!
 

Input
The input contains multiple test cases.

For each test case, the first line contains one integer  N(1N100000). Then next N lines contain N strings and the total length of N strings is between 1 and 100000. The next line contains one integer  Q(1Q100000). We define a specail integer Z=0. For each query, you get two integer L, R(0=
 

Output
For each question, output the answer.
 

Sample Input
 
   
3 abc aba baa 3 0 2 0 1 1 1
 

Sample Output
 
   
7 6 3

solution:

 
   

参考 SPOJ DQUERY 我们知道

/*

对于一个数

如果以前没出现过

就插入到主席树中

否则就删除以前那个。

再插入主席树。

注意,所有的更新和删除都是建立了新的节点来保持其历史状态的。。

对于hd[i]我们存的是从1到i区间的不同的数出现了多少个。

然后这棵树是根据hd[i - 1]来建立的。

*/

那么对于这题,我们通过字典树对每一个串的每一个前缀进行查找

如果以前没出现过,就插入到主席树中

否则就删除以前那个,再插入主席树。

模仿kuangbin代码写的


//字典树+主席树(kuangbin版本)
//可参考SPOJ DQUERY代码写
#include 
#include
#include
#include
#include
using namespace std;
const int maxn = 1e5 + 20;
int ls[maxn * 40], rs[maxn * 40], val[maxn * 40], hd[maxn], ntot;
string s[maxn];
int chd[maxn][26];
int tot, n;
int build(int l, int r)
{
	int rt = ntot++;
	val[rt] = 0;
	if (l = !r)
	{
		int mid = (l + r) >> 1;
		ls[rt] = build(l, mid);
		rs[rt] = build(mid + 1, r);
	}
	return rt;
}
int modify(int rt, int pos, int w)
{
	int newroot = ntot++, tmp = newroot;
	val[newroot] = val[rt] + w;
	int l = 1, r = n;
	while (l < r)
	{
		int mid = (l + r) >> 1;
		if (pos <= mid)
		{
			rs[newroot] = rs[rt]; ls[newroot] = ntot++;
			newroot = ls[newroot]; rt = ls[rt];
			r = mid;
		}
		else
		{
			ls[newroot] = ls[rt]; rs[newroot] = ntot++;
			newroot = rs[newroot]; rt = rs[rt];
			l = mid + 1;
		}
		val[newroot] = val[rt] + w;
	}
	return tmp;
}
int query(int rt, int pos)
{
	int res = 0;
	int l = 1, r = n;
	while (pos > l)
	{
		int mid = (l + r) >> 1;
		if (pos <= mid)
		{
			res += val[rs[rt]];
			rt = ls[rt];
			r = mid;
		}
		else
		{
			rt = rs[rt];
			l = mid + 1;
		}
	}
	return res + val[rt];
}
void Insert(string& str)
{
	int cur = 0;
	for (int i = 0; i < str.size(); i++)
	{
		int p = str[i] - 'a';
		if (chd[cur][p] == 0)
		{
			tot++;
			chd[cur][p] = tot;
			memset(chd[tot], 0, sizeof(chd[tot]));
		}
		cur = chd[cur][p];
	}
}
int pos[maxn];
void init()
{
	ntot = 0;
	memset(chd[0], 0, sizeof(chd[0]));
	memset(pos, 0, sizeof(pos));
	for (int i = 1; i <= n; i++)
		Insert(s[i]);
	tot = 0;
	hd[0] = build(1, n);
	for (int i = 1; i <= n; i++)
	{
		int cur = 0;
		hd[i] = hd[i - 1];
		for (int j = 0; j < s[i].size(); j++)
		{
			int p = s[i][j] - 'a';
			cur = chd[cur][p];
			if (pos[cur])
				hd[i] = modify(hd[i], pos[cur], -1);
			pos[cur] = i;
		}
		hd[i] = modify(hd[i], i, s[i].size());
	}
}
int main()
{
	while (~scanf("%d", &n))
	{
		int q, l, r, z = 0;
		for (int i = 1; i <= n; i++)
			cin >> s[i];
		init();
		scanf("%d", &q);
		while (q--)
		{
			scanf("%d%d", &l, &r);
			l = (z + l) % n + 1; r = (z + r) % n + 1;
			if (l > r) swap(l, r);
			z = query(hd[r], l);
			printf("%d\n", z);
		}
	}
	return 0;
}



你可能感兴趣的:(HDU,数据结构,线段树,主席树,字典树,多校赛,HDU)