大白书例题。
4种操作,插入操作可以像普通的排序二叉树那样插入,也可以利用2次伸展操作把第k-1个伸展到根节点,以及把根节点的右子树中的第一个伸展到根节点右子树节点,再把要插入的节点插入到右子树的左子树。
删除操作也可以像刚才一样,先把第k-1个伸展到根,再把右子树中第2个伸展到右子树处,这样右子树的左子树就是要删除的节点。
反转操作是通过类似刚才的操作提取那一段,再把这一段的左右子树交换,正反哈希值交换,同时打上一个标记用于下传。
查询2个后缀的LCP也类似,提取那一段,查询哈希值。
具体实现在最前面后最后分别加了一个节点,目的是刚才那个操作可能会k-1是0,以及查询哈希值的时候可能到末尾,因而提取操作的第二步是要把末尾的后一个伸展到根节点的右子树上,所以最后加了一个节点以防出错。
有些代码注掉的也是对的,不过用了别的方法,功能是一样的,效率上有差别。
AC代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
#define eps 1e-8
#define NMAX 201000
#define MOD 1000000007
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1)
template<class T>
inline void scan_d(T &ret)
{
char c;
int flag = 0;
ret=0;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c == '-')
{
flag = 1;
c = getchar();
}
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
if(flag) ret = -ret;
}
const int x = 137;
const int maxn = 200000+10;
ull X[maxn*2+10];
struct Node
{
Node* ch[2];
int num,s,flip;
ull hashv,rehashv;
int cmp(int x)
{
if(x == ch[0]->s+1) return -1;
if(x < ch[0]->s+1) return 0;
return 1;
}
void maintain()
{
s = ch[0]->s+ch[1]->s+1;
hashv = ch[0]->hashv + (ull)num*X[ch[0]->s] + ch[1]->hashv*X[ch[0]->s+1];
rehashv = ch[1]->rehashv + (ull)num*X[ch[1]->s] + ch[0]->rehashv*X[ch[1]->s+1];
}
void reverse()
{
swap(ch[0],ch[1]);
swap(hashv,rehashv);
flip ^= 1;
}
void pushdown()
{
if(flip)
{
flip = 0;
ch[0]->reverse();
ch[1]->reverse();
}
}
};
Node* null = new Node();
void node_init(Node* &o, int num)
{
o->ch[0] = o->ch[1] = null;
o->num = o->hashv = o->rehashv = num;
o->s = 1;
o->flip = 0;
}
void rotate(Node* &o, int d)
{
Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
o->maintain(); k->maintain(); o = k;
}
void splay(Node* &o, int k)
{
o->pushdown();
int d = o->cmp(k);
if(d == 1) k -= o->ch[0]->s+1;
if(d != -1)
{
Node* p = o->ch[d];
p->pushdown();
int d2 = p->cmp(k);
if(d2 == 1) k -= p->ch[0]->s+1;
if(d2 != -1)
{
splay(p->ch[d2],k);
if(d == d2) rotate(o,d^1);
else rotate(o->ch[d],d);
}
rotate(o,d^1);
}
}
void insert(Node* &o, int pos, int val)
{
o->pushdown();
int d = (pos <= o->ch[0]->s+1) ? 0 : 1;
if(d == 1) pos -= o->ch[0]->s+1;
if(o->ch[d] == null)
{
o->ch[d] = new Node();
node_init(o->ch[d],val);
o->maintain();
return;
}
insert(o->ch[d],pos,val);
o->maintain();
// splay(o,pos-1);
// splay(o->ch[1],1);
// o->ch[1]->ch[0] = new Node();
// node_init(o->ch[1]->ch[0],val);
// o->ch[1]->maintain();
// o->maintain();
}
void del(Node* &o, int pos)
{
splay(o,pos);
Node *left = o->ch[0], *right = o->ch[1];
delete o;
splay(left,left->s);
left->ch[1] = right;
o = left;
o->maintain();
// splay(o,pos-1);
// splay(o->ch[1],2);
// o->ch[1]->ch[0] = null;
// o->ch[1]->maintain();
// o->maintain();
}
//Node* merge(Node* left, Node* right)
//{
// splay(left,left->s);
// left->ch[1] = right;
// left->maintain();
// return left;
//}
//void split(Node* o, int k, Node* &left, Node* &right)
//{
// splay(o,k);
// left = o;
// right = o->ch[1];
// left->ch[1] = null;
// left->maintain();
//}
void dfs(Node* &o)
{
if(o != null)
{
o->pushdown();
dfs(o->ch[0]);
if(o->num != -1) printf("%d",o->num);
dfs(o->ch[1]);
}
}
char s[maxn];
void build(Node* &o, int n, int ge)
{
int p = (n+1)/2;
o = new Node();
node_init(o,s[ge+p-1]-'0');
if(p > 1) build(o->ch[0],p-1,ge);
if(n-p >= 1) build(o->ch[1],n-p,ge+p);
o->maintain();
}
void buildit(Node* &o, int n)
{
o = new Node();
node_init(o,-1);//最前面
o->ch[1] = new Node();
node_init(o->ch[1],-1);//最后面
build(o->ch[1]->ch[0],n,0);
o->ch[1]->maintain();
o->maintain();
}
void removetree(Node* &o)
{
if(o == NULL) return;
removetree(o->ch[0]);
removetree(o->ch[1]);
delete o;
o = NULL;
}
Node* root;
ull gethash(int x, int y)
{
splay(root,x-1);
splay(root->ch[1],y-x+2);
root->ch[1]->maintain();
root->maintain();
return root->ch[1]->ch[0]->hashv;
}
int main()
{
#ifdef GLQ
freopen("input.txt","r",stdin);
// freopen("o3.txt","w",stdout);
#endif
X[0] = 1;
for(int i = 1; i <= maxn*2; i++)
X[i] = X[i-1]*(ull)x;
null->s = null->hashv = null->rehashv = 0;
int n,m;
while(~scanf("%d%d",&n,&m))
{
scanf("%s",s);
// if(root != NULL) removetree(root);
buildit(root,n);
while(m--)
{
int type,p1,p2;
scanf("%d",&type);
if(type == 1)
{
scanf("%d%d",&p1,&p2);
insert(root,p1+2,p2);
// dfs(root);
// cout<<endl;
}
else if(type == 2)
{
scanf("%d",&p1);
del(root,p1+1);
// dfs(root);
// cout<<endl;
}
else if(type == 3)
{
scanf("%d%d",&p1,&p2);
p1++; p2++;
// Node *left,*mid,*right,*o;
// split(root,p1-1,left,o);
// split(o,p2-p1+1,mid,right);
// mid->reverse();
// root = merge(merge(left,mid),right);
splay(root,p1-1);
splay(root->ch[1],p2-p1+2);
root->ch[1]->ch[0]->reverse();
root->ch[1]->maintain();
root->maintain();
// dfs(root);
// cout<<endl;
}
else
{
scanf("%d%d",&p1,&p2);
p1++; p2++;
int l = 1,r = root->s-2-max(p1,p2)+2;
int ans = 0;
while(l <= r)
{
int mid = (l+r)>>1;
if(gethash(p1,p1+mid-1) == gethash(p2,p2+mid-1))
{
ans = mid;
l = mid+1;
}
else r = mid-1;
}
printf("%d\n",ans);
}
}
}
return 0;
}