_bzoj1014 [JSOI2008]火星人prefix【Splay】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1014

天,写kth()时,把判断条件k <= siz[ch[x][0]]错写成了k <= ch[x][0],RE不停,还爆掉了几个小时,以后写数据结构题一定要头脑清晰啊!

#include <cstdio>
#include <cstring>

const int maxn = 300005, base = 131;

int fa[maxn], ch[maxn][2], key[maxn], siz[maxn], root, cnt;
unsigned long long hash[maxn], poww[maxn];
int n, m, t1, t2, stk[maxn], top;
char s[maxn], opr, t3;

inline void pushup(int x) {
	hash[x] = hash[ch[x][0]] * (poww[siz[ch[x][1]] + 1]) + key[x] * poww[siz[ch[x][1]]] + hash[ch[x][1]];
	siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
}
inline void rotate(int x) {
	int y = fa[x];
	if (y == ch[fa[y]][0]) {
		ch[fa[y]][0] = x;
	}
	else {
		ch[fa[y]][1] = x;
	}
	fa[x] = fa[y];
	int dir = x == ch[y][1];
	ch[y][dir] = ch[x][dir ^ 1];
	fa[ch[x][dir ^ 1]] = y;
	ch[x][dir ^ 1] = y;
	fa[y] = x;
	pushup(y);
	pushup(x);
}
inline void splay(int x, int rt) {
	int p;
	while (fa[x] != rt) {
		p = fa[x];
		if (fa[p] == rt) {
			rotate(x);
		}
		else {
			if ((p == ch[fa[p]][1]) ^ (x == ch[p][1])) {
				rotate(x);
			}
			else {
				rotate(p);
			}
			rotate(x);
		}
	}
	if (!rt) {
		root = x;
	}
}
int make_tree(int left, int right) {
	if (left > right) {
		return 0;
	}
	int rt = (left + right) >> 1;
	key[rt] = s[rt];
	ch[rt][0] = make_tree(left, rt - 1);
	fa[ch[rt][0]] = rt;
	ch[rt][1] = make_tree(rt + 1, right);
	fa[ch[rt][1]] = rt;
	pushup(rt);
	return rt;
}
inline int kth(int k) {
	int x = root;
	while (k != siz[ch[x][0]] + 1) {
		if (k <= siz[ch[x][0]]) {
			x = ch[x][0];
		}
		else {
			k -= siz[ch[x][0]] + 1;
			x = ch[x][1];
		}
	}
	return x;
}
inline void modify(int root1, int root2) {
	root1 = kth(root1);
	root2 = kth(root2);
	splay(root1, 0);
	splay(root2, root1);
}
inline void ist(int pos, int _key) {
	modify(pos, pos + 1);
	++cnt;
	hash[cnt] = key[cnt] = _key;
	siz[cnt] = 1;
	ch[ch[root][1]][0] = cnt;
	fa[cnt] = ch[root][1];
	pushup(ch[root][1]);
	pushup(root);
}
/*void ist(int x, int k, int _key) {
	if (k == siz[ch[x][0]] + 1) {
		if (ch[x][1]) {
			top = 0;
			int i;
			for (i = ch[x][1]; ch[i][0]; i = ch[i][0]) {
				stk[top++] = i;
			}
			++cnt;
			ch[i][0] = cnt;
			fa[cnt] = i;
			key[cnt] = _key;
			siz[cnt] = 1;
			pushup(i);
			for (i = top - 1; ~i; --i) {
				pushup(stk[i]);
			}
		}
		else {
			++cnt;
			ch[x][1] = cnt;
			fa[cnt] = x;
			key[cnt] = _key;
		}
		pushup(x);
		splay(cnt, 0);
		return;
	}
	if (k <= siz[ch[x][0]]) {
		ist(ch[x][0], k, _key);
	}
	else {
		ist(ch[x][1], k - siz[ch[x][0]] - 1, _key);
	}
}*/
void upd(int x, int k, int _key) {
	if (k == siz[ch[x][0]] + 1) {
		key[x] = _key;
		pushup(x);
		return;
	}
	if (k <= siz[ch[x][0]]) {
		upd(ch[x][0], k, _key);
	}
	else {
		upd(ch[x][1], k - siz[ch[x][0]] - 1, _key);
	}
	pushup(x);
}
unsigned long long gethash(int start, int end) {
	modify(start - 1, end + 1);
	return hash[ch[ch[root][1]][0]];
}

int main(void) {
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	scanf("%s", s + 2);
	n = strlen(s + 2);
	s[1] = s[n + 2] = ‘$‘;
	n += 2;
	cnt = n;
	poww[0] = 1;
	for (int i = 1; i < maxn; ++i) {
		poww[i] = poww[i - 1] * base;
	}
	root = make_tree(1, n);
	scanf("%d", &m);
	int left, right, mid;
	while (m--) {
		while ((opr = getchar()) < ‘A‘);
		scanf("%d", &t1);
		++t1;
		if (opr == ‘I‘) {
			while ((t3 = getchar()) < ‘a‘);
			ist(t1, t3);
			++n;
		}
		else if (opr == ‘R‘) {
			while ((t3 = getchar()) < ‘a‘);
			upd(root, t1, t3);
		}
		else {
			scanf("%d", &t2);
			++t2;
			left = 0;
			right = n - (t1 > t2? t1: t2);
			while (left != right) {
				mid = (left + right + 1) >> 1;
				if (gethash(t1, t1 + mid - 1) == gethash(t2, t2 + mid - 1)) {
					left = mid;
				}
				else {
					right = mid - 1;
				}
			}
			printf("%d\n", left);
		}
	}
	return 0;
}

  

时间: 2024-10-12 14:02:44

_bzoj1014 [JSOI2008]火星人prefix【Splay】的相关文章

BZOJ 1014: [JSOI2008]火星人prefix( splay + hash )

用splay维护序列, 二分+hash来判断LCQ.. #include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxn = 100009; const int P = 1000173169; ull K[maxn]; int N; char S[maxn]; struct Node { Node *ch[2], *p; int s, v; ull h; inline void

[BZOJ1014] [JSOI2008] 火星人prefix (splay &amp; 二分答案)

Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串: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,

【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

[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 1014 JSOI2008 火星人prefix Splay+Hash+二分

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

BZOJ-1014 [JSOI2008]火星人prefix (Splay+二分+hash)

题解: 用splay维护添加修改操作,然后二分hash判断长度. 操作一:对于查询区间[l,r]的hash值,显然将l-1旋到根,将r+1旋到根的右儿子,此时所求区间就是根的右儿子的左儿子了. 操作二:将要修改的位置旋到根,然后直接改就可以了. 操作三:要在x后面添加一个字符,显然将x旋到根,x+1旋到根的右儿子,然后直接加在根的右儿子的左儿子上就可以了. 1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio&g

bzoj 1014 [JSOI2008]火星人prefix (splay+二分答案+字符串hash)

题目大意:维护一个字符串,支持插入字符和替换字符的操作,以及查询该字符串两个后缀的最长公共前缀长度 乍一看以为是后缀数组,然而并没有可持久化后缀数组(雾) 看题解才知道这是一道splay题,首先要对splay维护区间信息有一定了解 splay维护,插入字符,替换字符 而它的字树内所有儿子的中序遍历的hash值也可以通过splay维护  (这个推导式似乎烂大街了) 而后缀就是把i-1拎到根节点,然后把n+1拎到根节点的右儿子上,它的左儿子表示的就是hash值 至于如何查公共前缀呢?二分答案啊!询问

bzoj 1014: [JSOI2008]火星人prefix hash &amp;&amp; splay

1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3154  Solved: 948[Submit][Status] Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,火星人

【BZOJ-1014】火星人prefix Splay + 二分 + Hash

1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5852  Solved: 1871[Submit][Status][Discuss] Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d