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

来源:互联网 发布:淘宝如何拆分订单发货 编辑:程序博客网 时间:2024/05/16 19:44

题意

给出初始的字符串。需要进行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
原创粉丝点击