您的位置:首页 > Web前端 > JavaScript

bzoj 1014 [JSOI2008]火星人prefix(splay+hash)

2016-03-20 15:17 627 查看
【题目链接】

http://www.lydsy.com/JudgeOnline/problem.php?id=1014

【题意】

给定一个字符串,要求提供修改一个字符,插入一个字符,查询两个后缀LCP的功能。

【思路】

  splay维护字符串的哈希值。因为要提供区间,splay采用先查找后调整至根的写法。

一个结点的hash值为:

ch[0]->h * X^(ch[1]->s+1)+v * X^(ch[1]->s)+ch[1]->h

对于一个询问每次二分长度,提取区间后比较hash值即可。

需要注意的是splay要提前在区间的左右两边各加上一个节点,不然会调用到null。

ull自然溢出相当于模2^64。

【代码】

#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
const int N = 5e5+10;
const int X = 27;

ll read() {
char c=getchar();
ll f=1,x=0;
while(!isdigit(c)) {
if(c=='-') f=-1; c=getchar();
}
while(isdigit(c))
x=x*10+c-'0',c=getchar();
return x*f;
}

char s
;
int n,q;
ull powx
;

struct Node* null;
struct Node {
int s,v; ull h;
Node* ch[2];
int cmp(int k) {
if(k==ch[0]->s+1) return -1;
return k<=ch[0]->s? 0:1;
}
void init(int x) {
v=h=x; s=1;
ch[0]=ch[1]=null;
}
void maintain() {
s=ch[0]->s+ch[1]->s+1;
h=ch[0]->h*powx[ch[1]->s+1]+v*powx[ch[1]->s]+ch[1]->h;
}
} *root,nodepool
; int nodesz=0;

void rot(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) {
int d=o->cmp(k);
if(d==1) k-=o->ch[0]->s+1;
if(d!=-1) {
Node* p=o->ch[d];
int d2=p->cmp(k),k2=(d2==0?k:k-p->ch[0]->s-1);
if(d2!=-1) {
splay(p->ch[d2],k2);
if(d==d2) rot(o,d^1); else rot(o->ch[d],d);
}
rot(o,d^1);
}
}
//return range (l,r]
//加过点后 s[l,r]=range(l,r+1)
Node*& range(int l,int r) {
splay(root,l);
splay(root->ch[1],r-l+1);
return root->ch[1]->ch[0];
}

Node* build(int l,int r)
{
if(r<l) return null;
int mid=l+r>>1;
Node* o=&nodepool[++nodesz];
o->init(s[mid]-'a'+1);
o->ch[0]=build(l,mid-1);
o->ch[1]=build(mid+1,r);
o->maintain();
return o;
}
void insert(int p,int v)
{
splay(root,p+1);
Node* o=&nodepool[++nodesz];
o->init(v);
o->ch[0]=root->ch[0]; o->ch[1]=null;
o->maintain();
root->ch[0]=o; root->maintain();
}
void change(int p,int v)
{
splay(root,p);
root->v=v;
root->maintain();
}

int main()
{
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
null=new Node();
scanf("%s",s+1);
int n=strlen(s+1);
s[0]='z'+1; s[++n]='z'+1; s[n+1]='\0';
scanf("%d",&q);
powx[0]=1;
FOR(i,1,n+q) powx[i]=powx[i-1]*X;
root=build(0,n);
while(q--) {
char op[2],val[2];
int x,y;
scanf("%s%d",op,&x);
if(op[0]=='R') {
scanf("%s",val);
change(x+1,val[0]-'a'+1);
} else
if(op[0]=='I') {
scanf("%s",val);
insert(x+1,val[0]-'a'+1);
} else {
scanf("%d",&y);
int len=root->s,L=0,R=0;
R=min(len-y-1,len-x-1);
while(L<R) {
int M=L+(R-L+1)/2;
ull H=range(x,x+M)->h;
H-=range(y,y+M)->h;
if(!H) L=M; else R=M-1;
}
printf("%d\n",L);
}

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: