1. 程式人生 > >[JSOI2008]火星人prefix splay+Hash

[JSOI2008]火星人prefix splay+Hash

Description 給你一個字串,每次有加字元和改字元兩種操作,讓你求從l開始的字尾和從r開始的字尾的最長公共字首。

Sample Input madamimadam 7 Q 1 7 Q 4 8 Q 10 11 R 3 a Q 1 7 I 10 a Q 2 11

Sample Output 5 1 0 2 1

這題一眼題, 但碼程式碼碼了一上午。。。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef unsigned long long ULL;
const ULL P = 131;
int _min(int x, int y) {return x < y ? x : y;}
int read() {
	int s = 0, o = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') o = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * o;
}

struct tnode {
	int son[2], f, c;
	ULL s, sum, lazy;
} t[250010]; int cnt, root;
char ss[110000];
ULL s[110000], o[250010];

int new_node(ULL s, int f) {
	int now = ++cnt;
	t[now].s = s; t[now].sum = s;
	t[now].c = 1; t[now].f = f;
	t[now].lazy = 1;
	return cnt;
}

void update(int now) {
	int lc = t[now].son[0], rc = t[now].son[1];
	t[now].c = 1 + t[lc].c + t[rc].c;
	t[now].sum = t[now].s * o[t[lc].c] + t[lc].sum + t[rc].sum * o[t[lc].c + 1];
}

void rotate(int x, int fx) {
	int f = t[x].f, ff = t[f].f;
	int r, R;
	
	r = t[x].son[fx], R = f;
	if(r != 0) t[r].f = R;
	t[R].son[1 ^ fx] = r;
	
	r = x; R = ff;
	t[r].f = R;
	if(t[R].son[0] == f) t[R].son[0] = r; else if(t[R].son[1] == f) t[R].son[1] = r;
	
	r = f, R = x;
	t[r].f = R;
	t[R].son[fx] = r;
	
	update(f);
	update(x);
}

void splay(int x, int rt) {
	while(t[x].f != rt) {
		int f = t[x].f, ff = t[f].f;
		if(ff == rt) {
			if(t[f].son[0] == x) rotate(x, 1);
			else rotate(x, 0);
		}
		else if(t[f].son[0] == x && t[ff].son[0] == f) rotate(f, 1), rotate(x, 1);
		else if(t[f].son[0] == x && t[ff].son[1] == f) rotate(x, 1), rotate(x, 0);
		else if(t[f].son[1] == x && t[ff].son[1] == f) rotate(f, 0), rotate(x, 0);
		else if(t[f].son[1] == x && t[ff].son[0] == f) rotate(x, 0), rotate(x, 1);
	} if(rt == 0) root = x;
}

int findip(int k) {
	int x = root;
	while(1) {
		if(k <= t[t[x].son[0]].c) x = t[x].son[0];
		else if(t[t[x].son[0]].c + 1 == k) return x;
		else k -= t[t[x].son[0]].c + 1, x = t[x].son[1];
	} return x;
}

void add(int x, int c) {
	x++; int h1 = findip(x), h2 = findip(x + 1);
	splay(h2, 0), splay(h1, h2);
	t[h1].son[1] = new_node(c, h1);
	update(h1), update(h2);
}

ULL query(int l, int r) {
	l++, r++;
	int x = findip(l - 1), y = findip(r + 1);
	splay(x, 0), splay(y, x);
	return t[t[y].son[0]].sum;
}

void change(int x, int c) {
	x++; int hh = findip(x);
	splay(hh, 0);
	t[hh].s = c;
	update(hh);
}

int build(int l, int r) {
	if(l > r) return 0;
	int mid = (l + r) / 2;
	int now = mid;
	t[now].c = 1;
	t[now].s = s[mid];
	t[now].lazy = 1;
	t[now].son[0] = build(l, mid - 1);
	t[now].son[1] = build(mid + 1, r);
	if(t[now].son[0]) t[t[now].son[0]].f = now;
	if(t[now].son[1]) t[t[now].son[1]].f = now;
	update(now); return now;
}

int main() {
	scanf("%s", ss + 1);
	int n = strlen(ss + 1);
	int m = read();
	o[0] = 1;
	for(int i = 1; i <= n + m; i++) o[i] = o[i - 1] * P;
	for(int i = 1; i <= n; i++) s[i + 1] = ss[i];
	root = build(1, n + 2); cnt = n + 2; int N = n;
	for(int i = 1; i <= m; i++) {
		scanf("%s", ss + 1);
		if(ss[1] == 'Q') {
			int x = read(), y = read();
			int l = 1, r = _min(N - x + 1, N - y + 1), ans = 0;
			while(l <= r) {
				int mid = (l + r) / 2;
				if(query(x, x + mid - 1) == query(y, y + mid - 1)) l = mid + 1, ans = mid;
				else r = mid - 1;
			} printf("%d\n", ans);
		} else if(ss[1] == 'R') {
			int x = read(); scanf("%s", ss + 1);
			change(x, ss[1]);
		} else {
			int x = read(); scanf("%s", ss + 1);
			add(x, ss[1]); N++;
		}
	}
	return 0;
}