无旋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
*/

 

posted @   夏天海里的余  阅读(313)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示