8.26 T4 日记和编辑器(fhq维护kmp——kmp本身含有的单射与可合并性)

http://cplusoj.com/d/senior/p/NOD2301D

前4个操作拿fhq treap是很好维护的。

对于最后一个操作,我们可以这么思考,从kmp的匹配思路出发:

如果我们知道一个串进入的指针 j j j(也就是kmp匹配到的位置),我们是可以直接预处理得到出来的 j ′ j' j 的。

而这个东西是非常好pushup的!我们直接按照左、中、右的顺序就行了。

然后就做完了

#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
 #define debug(...) fprintf(stdout, ##__VA_ARGS__)
 #define debag(...) fprintf(stderr, ##__VA_ARGS__)
#else
 #define debug(...) void(0)
 #define debag(...) void(0)
#endif
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//#define M
//#define mo
#define N 1000010
int n, m, i, j, k, T, rt, Len;
char s[N], str[30], Ps[N]; 
int Q, c, u, fail[30]; 
int Gr[30][30], Fr[30][30]; 

struct FHQ_treap {
	int pri[N], w[N], a[N], cnt[N][30], f[N][30], g[N][30]; 
	int ls[N], rs[N], tot; 
	void push_up(int k) {
		int i; 
		w[k] = 1 + w[ls[k]] + w[rs[k]]; 
		for(i = 1; i <= 26; ++i) 
			cnt[k][i] = cnt[ls[k]][i] + cnt[rs[k]][i] + (a[k] == i); 
		for(i = 0; i <= Len; ++i) {
			g[k][i] = 0; f[k][i] = i; 
			if(ls[k]) g[k][i] += g[ls[k]][f[k][i]], f[k][i] = f[ls[k]][f[k][i]]; 
			g[k][i] += Gr[a[k]][f[k][i]]; f[k][i] = Fr[a[k]][f[k][i]]; 
			if(rs[k]) g[k][i] += g[rs[k]][f[k][i]], f[k][i] = f[rs[k]][f[k][i]]; 
		}
	}
	int merge(int x, int y) {
		if(!x || !y) return x + y; 
		if(pri[x] < pri[y]) {
			rs[x] = merge(rs[x], y); push_up(x); 
			return x; 
		}
		else {
			ls[y] = merge(x, ls[y]); push_up(y); 
			return y; 
		}
	}
	void split(int k, int lim, int &x, int &y) {
		if(!k) return x = y = 0, void(); 
		if(w[ls[k]] + 1 > lim) {
			y = k; split(ls[k], lim, x, ls[y]); 
		}
		else {
			x = k; split(rs[k], lim - w[ls[x]] - 1, rs[x], y); 
		}
		push_up(k); 
	}
	int new_node(int c) {
		++tot; cnt[tot][c]++; w[tot] = 1; a[tot] = c; pri[tot] = rand(); 
		for(int i = 0; i <= Len; ++i) 
			f[tot][i] = Fr[c][i], g[tot][i] = Gr[c][i]; 
		return tot; 
	}
	void print(int x) {
		if(!x) return ; 
		print(ls[x]); 
		printf("%c", (char)(a[x] + 'a' - 1)); 
		print(rs[x]); 
	}
}fhq;

signed main()
{
	#ifdef LOCAL
	  freopen("in.txt", "r", stdin);
	  freopen("out.txt", "w", stdout);
	#endif
//	srand(time(NULL));
//	T=read();
//	while(T--) {
//
//	}
	Q = read(); scanf("%s", Ps + 1); Len = strlen(Ps + 1); 
	for(i = 1; i <= Len; ++i) Ps[i] = Ps[i] - 'a' + 1; 
	for(i = 2; i <= Len; ++i) {
		u = fail[i - 1]; 
		while(u && Ps[u + 1] != Ps[i]) u = fail[u]; 
		if(Ps[u + 1] == Ps[i]) ++u; 
		fail[i] = u; 
	}
	for(i = 1; i <= Len; ++i) debug("%d ", fail[i]); debug("\n"); 
	for(c = 1; c <= 26; ++c) 
		for(i = 0; i <= Len; ++i) {
			u = i; 
			while(u && Ps[u + 1] != c) u = fail[u]; 
			if(Ps[u + 1] == c) ++u; 
			Fr[c][i] = u; Gr[c][i] = (u == Len);
			if(Fr[c][i]) debug("(%c %d) %d %d\n", c + 'a' - 1, i, Fr[c][i], Gr[c][i]); 
		}
	while(Q--) { 
		int x, y, z, l, r; 
		scanf("%s", str); 
		if(str[0] == 'D' || str[0] == 'R') {
			l = read(); r = read(); 
			fhq.split(rt, r, y, z); fhq.split(y, l - 1, x, y); 
			rt = fhq.merge(x, z); 
		}
		if(str[0] == 'I' || str[0] == 'R') {
			if(str[0] == 'I') j = read(); 
			else j = l - 1; 
			fhq.split(rt, j, x, y); z = 0; 
			scanf("%s", s + 1); m = strlen(s + 1); 
			for(i = 1; i <= m; ++i) {
				k = fhq.new_node(s[i] - 'a' + 1); 
				z = fhq.merge(z, k); 
			}
//			fhq.print(x); debug("\n"); 
//			fhq.print(y); debug("\n"); 
//			fhq.print(z); debug("\n"); 
			rt = fhq.merge(fhq.merge(x, z), y); 
		}
		if(str[0] == 'C') {
			l = read(); r = read(); scanf("%s", s);
			fhq.split(rt, r, y, z); fhq.split(y, l - 1, x, y); 
			printf("%d\n", fhq.cnt[y][s[0] - 'a' + 1]); 
			rt = fhq.merge(fhq.merge(x, y), z); 
		}
		if(str[0] == 'S') {
			l = read(); r = read(); 
			fhq.split(rt, r, y, z); fhq.split(y, l - 1, x, y); 
			printf("%d\n", fhq.g[y][0]); 
			rt = fhq.merge(fhq.merge(x, y), z); 
		}
//		fhq.print(rt); debug("| %d\n", fhq.w[rt]); 
	}
	return 0;
}



  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值