BZOJ 2258 pku2758 Checking the Text 文本校对 Splay+Hash+二分

题目大意:初始给出一个字符串,下面有一些操作,可以在一个地方加一个字符,询问从两个地方开始最长的匹配长度。

思路:Splay维护Hash值,询问的时候二分一下就行了。它条件给的比较恶心,注意处理的时候按照他说的做就行了。

CODE:

#define _CRT_SECURE_NO_DEPRECATE

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 51010
#define BASE 2333
using namespace std;
#define WORKPATH (root->son[1]->son[0])

unsigned long long power[MAX];

struct SplayTree{
	int val,size;
	unsigned long long hash;
	SplayTree *son[2],*father;

	SplayTree(int _);
	SplayTree() {}
	void Combine(SplayTree *a,bool dir) {
		son[dir] = a;
		a->father = this;
	}
	bool Check() {
		return father->son[1] == this;
	}
	void PushUp() {
		size = son[0]->size + son[1]->size + 1;
		hash = son[0]->hash + val * power[son[0]->size] + son[1]->hash * power[son[0]->size + 1];
	}
}*root,none,*nil = &none,*src[MAX];
SplayTree :: SplayTree(int _) {
	val = hash = _;
	size = 1;
	son[0] = son[1] = nil;
}

void Pretreatment()
{
	power[0] = 1;
	for(int i = 1; i < MAX; ++i)
		power[i] = power[i - 1] * BASE;
	nil->son[0] = nil->son[1] = nil->father = nil;
}

char s[MAX];

SplayTree *BuildTree(int l,int r)
{
	if(l > r)	return nil;
	int mid = (l + r) >> 1;
	SplayTree *re = new SplayTree(s[mid]);
	src[mid] = re;
	re->Combine(BuildTree(l,mid - 1),false);
	re->Combine(BuildTree(mid + 1,r),true);
	re->PushUp();
	return re;
}

inline void Rotate(SplayTree *a,bool dir)
{
	SplayTree *f = a->father;
	f->son[!dir] = a->son[dir];
	f->son[!dir]->father = f;
	a->son[dir] = f;
	a->father = f->father;
	f->father->son[f->Check()] = a;
	f->father = a;
	f->PushUp();
	if(root == f)	root = a;
}

inline void Splay(SplayTree *a,SplayTree *aim)
{
	while(a->father != aim) {
		if(a->father->father == aim)
			Rotate(a,!a->Check());
		else if(!a->father->Check()) {
			if(!a->Check())
				Rotate(a->father,true),Rotate(a,true);
			else	Rotate(a,false),Rotate(a,true);
		}
		else {
			if(a->Check())
				Rotate(a->father,false),Rotate(a,false);
			else	Rotate(a,true),Rotate(a,false);
		}
	}
	a->PushUp();
}

SplayTree *Find(SplayTree *a,int k)
{
	if(a->son[0]->size >= k)	return Find(a->son[0],k);
	k -= a->son[0]->size;
	if(k == 1)	return a;
	return Find(a->son[1],k - 1);
}

int asks;
int length;

inline unsigned long long GetHash(int l,int len)
{
	int l_size;
	Splay(src[l],nil),l_size = root->son[0]->size + 1;
	if(l_size + len > length + 2)	throw false;
	Splay(Find(root,l_size - 1),nil);
	Splay(Find(root,l_size + len),root);
	return WORKPATH->hash;
}

inline bool Judge(int x,int y,int ans)
{
	unsigned long long l,r;
	try{
		l = GetHash(x,ans);
		r = GetHash(y,ans);
	}
	catch(bool) {
		return false;
	}
	return l == r;
}

int main()
{
	Pretreatment();
	scanf("%s",s + 1);
	length = strlen(s + 1);
	root = BuildTree(0,length + 1);
	root->father = nil;
	cin >> asks;
	for(int x,y,i = 1; i <= asks; ++i) {
		scanf("%s",s);
		if(s[0] == 'Q') {
			scanf("%d%d",&x,&y);
			int l = 0,r = length,ans = 0;
			while(l <= r) {
				int mid = (l + r) >> 1;
				if(Judge(x,y,mid))	l = mid + 1,ans = mid;
				else	r = mid - 1;
			}
			printf("%d\n",ans);
		}
		else {
			scanf("%s%d",s,&x);
			if(x > length)	x = length + 1;
			++length;
			Splay(Find(root,x),nil);
			Splay(Find(root,x + 1),root);
			root->son[1]->Combine(new SplayTree(s[0]),false);
			root->son[1]->PushUp();
			root->PushUp();
		}
	}
	return 0;
}

时间: 2024-11-16 11:46:20

BZOJ 2258 pku2758 Checking the Text 文本校对 Splay+Hash+二分的相关文章

BZOJ 2258 pku2758 Checking the Text 文本校对 Splay+Hash

题目大意:给定一个字符串,多次插入一个字符和询问某两个后缀的LCP Splay+Hash.同1014 这逗比的询问...... #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 50500 #define BASE 151 using namespace std; typedef unsigned long long ll; stru

【BZOJ】1014: [JSOI2008]火星人prefix(splay+hash+二分+lcp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 被sb错调哭了QAQ...insert那里..插入到第x个后边...我......写成了第x个前面..........还调了!好!久! QAQ 本题神lcp做法....表示只会sa的height的离线.......这种在线的我就QAQ做个忧伤的表情... 然后膜拜了题解....好神..splay维护区间...hash+二分维护lcp....QAQ似乎是白书上说的么... 但是这种有概率的题这

【bzoj1014】[JSOI2008]火星人prefix Splay+Hash+二分

题目描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串,两个字串的公共前缀的长度.比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0

BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分

题目大意:给定一个字符串,提供下列操作: 1.查询从x开始的后缀和从y开始的后缀的最长公共前缀长度 2.将x位置的字符修改为y 3.在x位置的字符后面插入字符y 看到这题一开始我先懵住了...这啥..我第一时间想到的是后缀数据结构 但是不会写 而且后缀数据结构也不支持修改操作 后来无奈找了题解才知道是Hash+二分... 太强大了 Hash+二分打爆一切啊 用Splay维护这个字符串的修改和插入操作 每个节点维护子串的Hash值 判断时二分找到最长公共前缀 不过这道题还有一些注意事项 1.此题不

bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)

题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符. 前几天刚学了hash+二分求lcp,就看到这题. 原来splay还能这么用?!原来splay模板这么好写?我以前写的splay是假的吧woc splay每个节点代表一个字符,并维护这个子树代表一个子串的哈希值.因为splay旋转不破坏树结构,所以不论怎么旋转这棵splay树都能代表这个字符串. 预处理处理少了调了半天呜呜呜 赶紧跑去更新自己的splay模板 #include<iostream> #include&

poj 2758 &amp;&amp; BZOJ 2258 Checking the Text 文本校对

Description   为了给Wind买生日礼物,Jiajia不得不找了一份检查文本的工作.这份工作很无聊:给你一段文本 要求比对从文本中某两个位置开始能匹配的最大长度是多少.但比无聊更糟糕的是,Jiajia的经理 还可能往文本里面插入一些字符. Jiajia想用一个程序来解决这些繁琐的工作.这个程序的速度要足够快,因为Wind的生日就快要到了 Jiajia必须赚到足够多的钱,也就是处理足够多的文本. Input 输入文件第一行是原始文本. 输入文件第二行是操作数n.此后n行,每行描述一条命

UVa 11996 Jewel Magic (splay + Hash + 二分)

题意:给定一个长度为n的01串,你的任务是依次执行如表所示的m条指令: 1 p c 在第p个字符后插入字符,p = 0表示在整个字符串之前插入2 p 删除第p个字符,后面的字符往前移3 p1 p2反转第p1到第p2个字符4 p1 p2输出从p1开始和p2开始的两个后缀的LCP. 析:对于前三个操作,splay 很容易就可以解决,但是对于最后一个操作,却不是那么容易,因为这是动态的,所以我们也要维护一个可以动态的,这就可以用Hash来解决,由于要翻转,所以要维护两个,一个正向的,一个反向的.在操作

[BZOJ1014][JSOI2008]火星人prefix splay+hash+二分

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1014 先考虑如果没有修改操作和插入操作,是一个静态的字符串,我们可以怎样快速求得题目中的LCQ. 两个字符串判等很容易想到hash.于是我们二分答案并二分判断,就可以在$log_n$时间内得到答案. 现在加上修改和插入操作,其实就是要动态维护子串也就是一段区间的hash值,这种问题很容易就想到用splay来维护. 每个节点记录此节点管辖下子树的hash值h,当前节点的h=左孩子的h+节点

BZOJ 2565 最长双回文串 Hash+二分

题目大意:给定一个字符串,求一个最长的子串,该字串可以分解为两个回文子串 傻逼的我又忘了Manacher怎么写了= = 无奈Hash+二分吧 首先将字符串用分隔符倍增,然后求出以每个点为中心的最长回文半径 然后考虑两个回文串怎么合并成一个 我们发现图中以i为中心的回文串和以j为中心的回文串合并后长度恰好为(j-i)*2 能合并的前提是以两个点为中心的回文串有交点 那么对于每个j我们要求出有交点的最左侧的i 维护一个后缀min随便搞搞就可以了 #include <cstdio> #include