[splay+二分+哈希] BZOJ1014: [JSOI2008]火星人prefix

题意

给出初始的字符串。需要进行M次操作描,操作有3种:
1.询问LCQ(x,y)。2.修改单个字符。3.插入单个字符。
其中LCQ(x,y)表示字符串x~len与y~len的最长公共前缀的长度。(len为当前串长)
M<=10^5

题解

对于静态的LCQ问题,我们可以对所有后缀排个序搞一搞实现,但是有了修改操作后就不行了,要另想办法。发现字符串的变化很自由,非常难控制,所以只好上大数据结构了,我们用splay维护序列,能解决修改问题。
但是询问操作如何实现呢?
splay并不能维护一些特别的信息,感觉很难办。注意到答案有二分性,是否能每次二分答案呢?要实现二分,需要快速比较两个长度相同的字符串是否相同。其实哈希一下就行了,实际效果是可以信赖的。哈希的值我们在splay中就可以维护了。
时间复杂度: O(nlog2n)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL MOD=1000000007;
LL p[100005];
struct node{
    LL key,size,val;
    node *ch[2];
    void maintain(){
        size=ch[0]->size+ch[1]->size+1; 
        val=(p[ch[1]->size+1]*ch[0]->val+key*p[ch[1]->size]+ch[1]->val)%MOD;
    }
    int cmp(int &k){
        if(k<=ch[0]->size) return 0;
        if(k>ch[0]->size+1){ k-=ch[0]->size+1; return 1;}
        return -1;
    } 
} nil,base[200005],*null=&nil,*root,*t_len;
typedef node* P_node;
void Splay_init(){  null->size=null->val=0; null->ch[0]=null->ch[1]=null; t_len=base; }
void rot(P_node &p,int d){
    P_node k=p->ch[d^1]; p->ch[d^1]=k->ch[d]; k->ch[d]=p;
    p->maintain(); k->maintain(); p=k; 
}
void splay(P_node &p,int k){    
    int d1=p->cmp(k);
    if(d1!=-1){
        P_node p2=p->ch[d1];
        int d2=p2->cmp(k);
        if(d2!=-1){
            splay(p2->ch[d2],k);
            if(d1==d2) rot(p,d1^1), rot(p,d1^1); 
                  else rot(p->ch[d1],d2^1), rot(p,d1^1);
        } else rot(p,d1^1);
    }
}
P_node newnode(int tkey){
    t_len->key=tkey; t_len->size=1; t_len->val=tkey;
    t_len->ch[0]=t_len->ch[1]=null;
    return t_len++;
}
char b[1000005];
P_node build(int L,int R){
    if(L>R) return null;
    int mid=(L+R)>>1;
    P_node p=newnode(b[mid]);
    p->ch[0]=build(L,mid-1); p->ch[1]=build(mid+1,R);
    p->maintain();
    return p;
}
P_node merge(P_node left,P_node right){
    splay(left,left->size); left->ch[1]=right;
    left->maintain(); return left;
}
void split(P_node p,int k,P_node &left,P_node &right){
    splay(p,k); left=p;
    right=p->ch[1]; p->ch[1]=null;
    left->maintain();
}
bool check(int x,int y,int now){
    P_node left,right;
    split(root,x-1,left,right); splay(right,now+1);
    int t1=right->ch[0]->val;
    root=merge(left,right);
    split(root,y-1,left,right); splay(right,now+1);
    int t2=right->ch[0]->val;
    root=merge(left,right); 
    return t1==t2;
}
int Q;
int main(){
    freopen("bzoj1014.in","r",stdin);
    freopen("bzoj1014.out","w",stdout);
    Splay_init();
    p[0]=1; for(int i=1;i<=100000;i++) p[i]=(p[i-1]*13)%MOD;
    scanf("%s",b+1); int len=strlen(b+1); 
    b[0]='['; b[len+1]=']'; 
    root=build(0,len+1);
    scanf("%d",&Q);
    while(Q--){
        char ch[5]; scanf("%s",ch);
        if(ch[0]=='Q'){
            int x,y; scanf("%d%d",&x,&y); x++; y++;
            int L=1,R=min(root->size-x,root->size-y),res=0;
            while(L<=R){
                int mid=(L+R)>>1;
                if(check(x,y,mid)) L=mid+1,res=mid;
                              else R=mid-1;
            }
            printf("%d\n",res);
        }
        if(ch[0]=='I'){
            int x; scanf("%d",&x); x++; getchar();char ch=getchar();
            P_node Left,Right; split(root,x,Left,Right);
            splay(Right,1); Right->ch[0]=newnode(ch); Right->maintain();
            root=merge(Left,Right);
        }
        if(ch[0]=='R'){
            int x; scanf("%d",&x); x++; getchar();char ch=getchar();
            P_node Left,Right; split(root,x,Left,Right);
            splay(Left,Left->size-1); Left->ch[1]=newnode(ch); Left->maintain();
            root=merge(Left,Right);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值