给一个长度为n的01串,m个操作:
1 p c :在第p位之后插入字符
2 p :删除第p位字符
3 p1 p2: 把从p1到p2位之间的字符翻转
4 p1 p2: 查询以p1,p2开始的字符串的最长公共前缀。
前三个操作可以直接用伸展树处理,查询lcp的话,可以给在每个节点记录一下该子树表示的字符串的hash值,这样在查询的时候就可以二分长度去求lcp了。
因为涉及到翻转操作,所以要求两个hash值,一个正向一个反向,在翻转的时候,直接交换这两个方向的hash值就行。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ull x=233;
const int maxn=502000;
int a[maxn],b[maxn];
char s[maxn];
ull H[2][maxn];
ull xp[maxn];
int size[maxn];
int pre[maxn],ch[maxn][2];
int flip[maxn];
int tot,root;
int n,m;
struct splaytree
{
void init()
{
tot=root=0;
newnode(root,0,0);
newnode(ch[root][1],root,0);
build(1,n,ch[ch[root][1]][0],ch[root][1]);
pushup(ch[root][1]);
pushup(root);
}
void pushup(int r)
{
if (r==0) return;
size[r]=size[ch[r][0]]+1+size[ch[r][1]];
H[1][r]=H[1][ch[r][0]]*xp[1+size[ch[r][1]]]+a[r]*xp[size[ch[r][1]]]+H[1][ch[r][1]];
H[0][r]=H[0][ch[r][0]]+a[r]*xp[size[ch[r][0]]]+H[0][ch[r][1]]*xp[size[ch[r][0]]+1];
}
void go_f(int r)
{
if (!r) return;
flip[r]^=1;
swap(H[0][r],H[1][r]);
swap(ch[r][0],ch[r][1]);
//