spoj STRLCP (數據結構 + hash)


題目鏈接

算是陳題了吧, 至少我都在兩個oj上都見過類似題目了, 最大的特徵就是查詢一個動態字符串某兩個後綴

的最長公共前綴, 做法就是用伸展樹動態維護區間的hash值, 每次查詢時二分答案, 然後每次判斷也是

log(n), 所以查詢的複雜度是log(n) ^ 2,其他操作都是log(n)。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <cstdlib>
#include <map>
#include <algorithm>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 250005 << 1;
typedef long long LL;
const int seed = 31;

LL xp[N];

char str[N];

void init() {
	xp[0] = 1;
	for (int i = 1; i < N; i++)
		xp[i] = xp[i - 1] * seed;
}


struct Splay {

	struct Node {
		Node* ch[2], * fa;
		LL h[2];
		char val;
		int sz;
		bool flip;

		void init(char v, Node* f, Node* x) {
			fa = f;
			val = v;
			h[0] = h[1] = v - 'a' + 1;
			flip = 0;
			sz = 1;
			ch[1] = ch[0] = x;
		}
	}D[N];
	
	Node* null, * root, * it;

	void init(int n) {
		null = new Node;
		null->sz = 0;
		null->ch[0] = null->ch[1] = null;
		null->fa = null;
		null->h[1] = null->h[0] = 0;
		null->flip = 0;
		null->val = 0;

		it = D;
		it->init(0, null, null);
		root = it++;

		it->init(0, root, null);
		root->ch[1] = it++;

		for (int i = 1; i <= n; i++) {
			insert(i, str[i - 1]);
		}
	}

	void push_down(Node* rt) {
		if (rt->flip) {
			update(rt->ch[0]);
			update(rt->ch[1]);
			rt->flip = 0;
		}
	}

	void update(Node* rt) {
		if (rt == null) return;
		rt->flip ^= 1;
		swap(rt->ch[0], rt->ch[1]);
		swap(rt->h[0], rt->h[1]);
	}

	void push_up(Node* rt) {
		rt->sz = rt->ch[0]->sz + rt->ch[1]->sz + 1;
		rt->h[0] = rt->ch[1]->h[0] + (rt->val - 'a' + 1) * xp[rt->ch[1]->sz] + rt->ch[0]->h[0] * xp[rt->ch[1]->sz + 1];
		rt->h[1] = rt->ch[0]->h[1] + (rt->val - 'a' + 1) * xp[rt->ch[0]->sz] + rt->ch[1]->h[1] * xp[rt->ch[0]->sz + 1];
	}

	void rotate(Node *x, int d) {
		Node *y = x->fa;
		push_down(y), push_down(x);

		y->ch[d ^ 1] = x->ch[d];
		if (x->ch[d] != null) x->ch[d]->fa = y;
		x->fa = y->fa;
		if (y->fa != null) {
			if (y->fa->ch[0] == y) 
				y->fa->ch[0] = x; 
			else 
				y->fa->ch[1] = x;
		}
		x->ch[d] = y, y->fa = x;
		push_up(y);
		if (y == root) root = x; // root 表示整棵樹的根結點
	}

	void splay(Node *x, Node *f) {
		for (push_down(x); x->fa != f; ) {
			if (x->fa->fa == f) // 父結點的父親即爲f,執行單旋轉
				if (x->fa->ch[0] == x) 
					rotate(x, 1); 
				else 
					rotate(x, 0);
			else {
				Node *y = x->fa, *z = y->fa;
				if (z->ch[0] == y)
					if (y->ch[0] == x)
						rotate(y, 1), rotate(x, 1);
					else
						rotate(x, 0), rotate(x, 1);
				else
					if (y->ch[1] == x)
						rotate(y, 0), rotate(x, 0);
					else
						rotate(x, 1), rotate(x, 0);
			}
		}
		push_up(x);
		if (f == null) root = x;
	}

	/*
	   void select(int k, Node *f) {
	   Node *t;
	   for (t = root; t != null; ) {
	   push_down(t);
	   int tmp = t->ch[0]->sz + 1;
	   if (k == tmp) break;
	   if (k < tmp)
	   t = t->ch[0];
	   else 
	   k -= tmp + 1, t = t->ch[1];
	   }
	   splay(t, f); 
	   }*/

	void insert(int p, char c) {
		select(p, null);
		select(p + 1, root);
		it->init(c, root->ch[1], null);
		root->ch[1]->ch[0] = it++;
		splay(root->ch[1]->ch[0], null);
	}

	void replace(int p, char c) {
		select(p - 1, null);
		select(p + 1, root);
		Node* t = root->ch[1]->ch[0];
		t->val = c;
		t->h[0] = t->h[1] = c - 'a' + 1;
		splay(t, null);
	}

	LL get_hash(int p1, int p2) {
		select(p1 - 1, null);
		select(p2 + 1, root);
		return root->ch[1]->ch[0]->h[0];
	}

	void reverse(int p1, int p2) {
		select(p1 - 1, null);
		select(p2 + 1, root);
		update(root->ch[1]->ch[0]);	
		splay(root->ch[1], null);
	}

	void select(int k, Node *f) {
		Node *x = root;
		while(x != null) {
			push_down(x);
			int tmp = x->ch[0]->sz + 1;
			if(k == tmp) break;
			else if(k > tmp) k -= tmp, x= x->ch[1];
			else x = x->ch[0];
		}
		splay(x, f);
	}

	int lcp(int p1, int p2) {
		int L = 1, R = root->sz - max(p1, p2);
		while (L <= R) {
			int mid = L + R >> 1;
			if (get_hash(p1, p1 + mid - 1) == get_hash(p2, p2 + mid - 1)) 
				L = mid + 1;
			else
				R = mid - 1;
		}
		return R;
       	}

}T;

int main() {
	int n, m, p1, p2, c, flag;
	int test;
	scanf("%d", &test);
	char s[3], op[3];
	init();
	while (test--) {
		scanf("%s%d", str, &m);
		n = strlen(str);
		T.init(n);
		for (int i = 0; i < m; i++) {
			scanf("%s", op);
			if (op[0] == 'I') {
				scanf("%d%s", &p1, s);
				p1++;
				T.insert(p1, s[0]); 
			}
			else if (op[0] == 'R') {
				scanf("%d%s", &p1, s);
				p1++;
				T.replace(p1, s[0]);		
			}
			else if (op[0] == 'Q') {
				scanf("%d%d", &p1, &p2);
				p1++, p2++;
				printf("%d\n", T.lcp(p1, p2));	
			}
		}
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章