zoukankan      html  css  js  c++  java
  • [BZOJ 1014] [JSOI2008] 火星人prefix 【Splay + Hash】

    题目链接:BZOJ - 1014

    题目分析

    求两个串的 LCP ,一种常见的方法就是 二分+Hash,对于一个二分的长度 l,如果两个串的长度为 l 的前缀的Hash相等,就认为他们相等。

    这里有修改字符和插入字符的操作,所以用 Splay 来维护串的 Hash 值。

    一个节点的值就是它的子树表示的字串的 Hash 值。

    使用 unsigned long long 然后自然溢出就不需要 mod 了,速度会快很多。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    
    using namespace std;
    
    inline int gmax(int a, int b) {return a > b ? a : b;}
    
    typedef unsigned long long ULL;
    
    const ULL Seed = 211;
    
    const int MaxN = 100000 + 5;
    
    int n, l, m, Root, Index;
    int Father[MaxN], Son[MaxN][2], Size[MaxN];
    
    ULL H[MaxN], Pow_Seed[MaxN]; 
    
    char Str[MaxN], T[MaxN];
    
    int NewNode(char c)
    {
    	int x = ++Index;
    	T[x] = c;
    	H[x] = (ULL)c;
    	Size[x] = 1;
    	return x;
    }
    
    inline void Update(int x)
    {
    	Size[x] = Size[Son[x][0]] + Size[Son[x][1]] + 1;
    	H[x] = (H[Son[x][0]] * Seed + T[x]) * Pow_Seed[Size[Son[x][1]]] + H[Son[x][1]];
    }
    
    int Build(int s, int t)
    {
    	int x, m = (s + t) >> 1;
    	x = NewNode(Str[m]);
    	if (s < m) 
    	{
    		Son[x][0] = Build(s, m - 1);
    		Father[Son[x][0]] = x;
    	}
    	if (t > m)
    	{
    		Son[x][1] = Build(m + 1, t);
    		Father[Son[x][1]] = x;
    	}
    	Update(x);
    	return x;		
    }
    
    inline int GetDir(int x)
    {
    	if (x == Son[Father[x]][0]) return 0;
    	else return 1;
    }
    
    void Rotate(int x)
    {
    	int y = Father[x], f = GetDir(x) ^ 1;
    	Father[x] = Father[y];
    	if (Father[y])
    	{
    		if (y == Son[Father[y]][0]) Son[Father[y]][0] = x;
    		else Son[Father[y]][1] = x;
    	}
    	Son[y][f ^ 1] = Son[x][f];
    	if (Son[x][f]) Father[Son[x][f]] = y;
    	Son[x][f] = y;
    	Father[y] = x;
    	Update(y); Update(x);
    }
    
    void Splay(int x, int d)
    {
    	int y;
    	while (Father[x] != d)
    	{
    		y = Father[x];
    		if (Father[y] == d)
    		{
    			Rotate(x);
    			break;
    		}
    		if (GetDir(y) == GetDir(x)) Rotate(y);
    		else Rotate(x);
    		Rotate(x);
    	}
    	if (Father[x] == 0) Root = x;
    }
    
    int Find(int Num)
    {
    	int x = Root, k = Num;	
    	while (Size[Son[x][0]] + 1 != k)
    	{
    		if (Size[Son[x][0]] + 1 > k) 
    			x = Son[x][0];
    		else
    		{
    			k -= Size[Son[x][0]] + 1;
    			x = Son[x][1];
    		}
    	}
    	return x;
    }
    
    bool Check(int p, int q, int len)
    {
    	if (len == 0) return true;
    	int x, y;
    	ULL Hp, Hq;
    	x = Find(p); 
    	y = Find(p + len + 1);
    	Splay(x, 0);
    	Splay(y, x);
    	Hp = H[Son[y][0]];
    	x = Find(q);
    	y = Find(q + len + 1);
    	Splay(x, 0);
    	Splay(y, x);
    	Hq = H[Son[y][0]];
    	
    	return Hp == Hq;
    }
    
    int main()
    {
    	Pow_Seed[0] = 1;
    	for (int i = 1; i <= 100000; ++i) 
    		Pow_Seed[i] = Pow_Seed[i - 1] * Seed;
    	scanf("%s", Str + 1);
    	l = strlen(Str + 1);
    	n = l;
    	Root = Build(0, l + 1);
    	scanf("%d", &m);
    	char f, ch;
    	int Pos, x, y, p, q, l, r, mid, Ans;
    	for (int i = 1; i <= m; ++i)
    	{
    		f = '-';
    		while (f < 'A' || f > 'Z') f = getchar();
    		switch (f)
    		{
    			case 'R' :
    				scanf("%d %c", &Pos, &ch);
    				x = Find(Pos + 1);
    				Splay(x, 0);
    				T[x] = ch;
    				H[x] = (ULL)ch;
    				Update(x);
    				break;
    			
    			case 'I' :
    				++n;
    				scanf("%d %c", &Pos, &ch);
    				x = Find(Pos + 1);
    				y = Find(Pos + 2);
    				Splay(x, 0);
    				Splay(y, x);
    				Son[y][0] = ++Index;
    				T[Index] = ch;
    				H[Index] = (ULL)ch;
    				Size[Index] = 1;
    				Father[Index] = y;
    				Update(y); Update(x);
    				break;
    			
    			case 'Q' : 
    				scanf("%d%d", &p, &q);
    				l = 0; r = n - gmax(p, q) + 1;
    				while (l <= r)
    				{
    					mid = (l + r) >> 1;
    					if (Check(p, q, mid)) 
    					{
    						Ans = mid;
    						l = mid + 1;
    					}
    					else r = mid - 1;
    				}
    				printf("%d
    ", Ans);
    				break;
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    团队编程项目作业3-模块测试过程
    团队编程项目作业3-模块开发过程
    课后作业-结队编程项目进度
    团队编程项目作业2-团队编程项目代码设计规范
    课后作业-阅读任务-阅读提问-1
    团队-爬取豆瓣电影Top250-项目总结
    团队-爬取豆瓣Top250-最终程序
    课后作业-阅读任务-阅读提问-4
    《20171129-构建之法:现代软件工程-阅读笔记》
    《软件工程课程总结》
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4454508.html
Copyright © 2011-2022 走看看