1. 程式人生 > 其它 >無旋Treap

無旋Treap

1 匹配(match.c/cpp/pas)
1.1 題目描述
給定一個僅含小寫字母的字串 S[0..n-1],對於一個詢問 (p, q, len),我們想知道它的
兩個子串 S[p..p+len-1]、S[q..q+len-1] 是否相同。更多地,我們希望在對串 S 完成一些操
作之後還能高效地得到這個結果。 我們具體要維護以下幾個操作(其中 L 為操作之前的串
長):
● 1 p c:在下標 p 之前插入一個小寫字母 c,0<=p<=L,p=0 意味在頭插入,p=L
意味在尾插入;
● 2 p: 刪除 S[p],其中 0<=p<L;
● 3 p q: 將 S[p..q] 翻轉為 S[q..p],例如 batta 經過 “3 1 3” 之後為 bttaa;
● 4 p q len: 表示一次詢問操作,詢問 S[p..p+len-1] 與 S[q..q+len-1] 是否相同,其
中 0<=p<=p+len-1<L,0<=q<=q+len-1<L。
1.2 輸入格式
第 1 行為兩個整數 n, m,分別表示字串的初始長度和操作次數;
 第 2 行為一個長度為 n 的字串;
接下來 m 行,每行為一個操作。
1.3 輸出格式
僅一行一個整數,表示詢問相同的次數。
1.4 樣例輸入
4 4
aacb
2 2 // aab
1 2 b // aabb
3 1 2 // abab
4 0 2 2 // ab == ab
1.5 樣例輸出
1
1.6 資料範圍與約定
對於前 20%的資料滿足 n,m≤1000;
對於前 70%的資料滿足僅含有 3、4 兩種操作;
對於 100%的資料滿足 1≤n, m≤200000。

平衡樹維護序列的裸題,考慮在每個結點維護以該結點為根的子樹的中序字串的雜湊值(記為 hash[u][0]),以及該字串翻轉後的雜湊值(記為 hash[u][1]),則有:hash[u][0] =hash[child[u][0]][0] * pow[size[child[u][1]] + 1] + character[u] * pow[size[child[u][1]]] +hash[child[u][1]][0],其中 child[u][0/1] 表示 u 的左/右兒子,size[u] 表示以 u 為根的子樹大小,pow[i] 表示雜湊的進位制 BASE 的 i 次方。hash[u][1] 的計算同理,有:hash[u][1] =hash[child[u][0]][1] + character[u] * pow[size[child[u][0]]] + hash[child[u][1]][1] *pow[size[child[u][0]] + 1]。
注意在給一個結點打上翻轉標記時,不僅要交換其左右兒子,還要交換 hash[u][0] 和hash[u][1] 的值。比較時通過區間提取,獲得兩個區間對應字串的雜湊值,然後直接判斷是否相等即可。這道題可直接自然溢位。

#include<bits/stdc++.h>
#define int long long
using namespace std;
mt19937 rnd(time(0));
int in() {
	int x = 0, f = 1;
	char ch;
	for(ch = getchar(); (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
	if(ch == '-')ch = getchar();
	do x = x * 10 + ch - '0', ch = getchar();
	while(ch >= '0' && ch <= '9');
	return x * f;
}
int root, tot = 0;
unsigned int pw1[800005], pw2[800005], bas2 = 233, bas1 = 421;
struct node {
	char ch;
	int rd, tag;
	int ls, rs, siz;
	unsigned int h1, h2;
	unsigned int hh1, hh2;
} q[800005];
int New(char ch) {
	q[++tot].ch = ch;
	q[tot].rd = rnd();
	q[tot].siz = 1;
	q[tot].h1 = q[tot].h2 = ch;
	q[tot].hh1 = q[tot].hh2 = ch;
	return tot;
}
void push(int o) {
	if(q[o].tag) {
		swap(q[o].h1, q[o].h2);
//		swap(q[o].hh1,q[o].hh2);
		swap(q[o].ls, q[o].rs);
		if(q[o].ls)q[q[o].ls].tag ^= 1;
		if(q[o].rs/**/)q[q[o].rs].tag ^= 1;
		q[o].tag = 0;
	}
}
void up(int o) {
	q[o].siz = q[q[o].ls].siz + q[q[o].rs].siz + 1;
	push(q[o].ls),push(q[o].rs);
	q[o].h1 = (q[q[o].ls].h1 + q[o].ch * pw1[q[q[o].ls].siz] + q[q[o].rs].h1 * pw1[q[q[o].ls].siz + 1]);
	q[o].h2 = (q[q[o].rs].h2 + q[o].ch * pw1[q[q[o].rs].siz] + q[q[o].ls].h2 * pw1[q[q[o].rs].siz + 1]);
//	q[o].hh1=(q[q[o].ls].hh1+q[o].ch*pw2[q[q[o].ls].siz]+q[q[o].rs].hh1*pw2[q[q[o].ls].siz+1]);
//	q[o].hh2=(q[q[o].rs].hh2+q[o].ch*pw2[q[q[o].rs].siz]+q[q[o].ls].hh2*pw2[q[q[o].rs].siz+1]);
}
void split(int o, int s, int &l, int &r) {
	if(!o) {
		l = r = 0;
		return;
	}
	push(o);//
	if(q[q[o].ls].siz + 1 <= s) {
		l = o;
		split(q[o].rs, s - q[q[o].ls].siz - 1, q[l].rs, r);
	} else {
		r = o;
		split(q[o].ls, s, l, q[r].ls);
	}
	up(o);//
}
int merge(int l, int r) {
	if(!l || !r)return l | r; //
	int o;
	if(q[l].rd <= q[r].rd) {
		push(l);
		o = l;
		q[o].rs = merge(q[l].rs, r);
	} else {
		push(r);
		o = r;
		q[o].ls = merge(l, q[r].ls);
	}
	up(o);//
	return o;
}
void write(int o) {
	if(!o)return;
	push(o);
	write(q[o].ls);
	putchar(q[o].ch);
	write(q[o].rs);
}
char s[800005];
signed main() {
	freopen("match.in", "r", stdin);
	freopen("match.out", "w", stdout);
	int n = in(), m = in();
	pw1[0] = pw2[0] = 1;
	for(int i = 1; i <= m + n; i++)pw1[i] = pw1[i - 1] * bas1;
	for(int i = 1; i <= m + n; i++)pw2[i] = pw2[i - 1] * bas2;
	scanf("%s", s + 1);
	for(int i = 1; i <= n; i++) {
		int o = New(s[i]);
		root =/**/merge(root, o);
	}
	int ans = 0;
	for(int i = 1; i <= m; i++) {
		int op = in();
		if(op == 1) {
			int p = in();
			char o = getchar();
			int x, y, z;
			split(root, p, x, y);
			z = New(o);
			root = merge(merge(x, z), y);
		}
		if(op == 2) {
			int p = in();
			int x, y, z;
			split(root, p, x, y);
			split(y, 1, y, z);
			root = merge(x, z);
		}
		if(op == 3) {
			int l = in(), r = in();
			int x, y, z;
			split(root, l, x, y);
			split(y, r - l + 1, y, z);
			q[y].tag ^= 1;
			root = merge(merge(x, y), z);
		}
		if(op == 4) {
			int l = in(), r = in(), len = in(), x, y, z;
			unsigned int h1, hh1, h2, hh2;
			split(root, l, x, y);
			split(y, len, y, z);
			h1 = q[y].h1; /*hh1=q[y].hh1;*/
			root = merge(merge(x, y), z);
			split(root, r, x, y);
			split(y, len, y, z);
			h2 = q[y].h1; /*hh2=q[y].hh1;*/
			root = merge(merge(x, y), z);
			if(h1 == h2/*&&hh1==hh2*/)ans++;
		}
//		write(root);
//		puts("");
	}
	printf("%lld", ans);
	return 0;
}
/*
4 4
aacb
2 2
1 2 b
3 1 2
4 0 2 2
*/