BZOJ1014 JSOI2008 火星人prefix HASH+平衡树+二分法

题意:给定一个字符串,维护:1、修改某个位置的字符  2、查询从p、q位置开始相同字串的长度  3、在某个位置后面插入一个字符

题解:因为需要支持修改所以很容易想到用平衡树,每个节点维护该节点子树所构成的字串的Hash值,修改和插入不用多说,查询我们二分答案,然后在Splay上查询即可。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

const int P=233;
const int MAXL=100000+2;
typedef struct NODE{
    int v,c,h;
    NODE *child[2],*f;
    NODE(){}
    NODE(int _v):v(_v),c(1),h(_v){}
} *TREE;
TREE root,Null;
int Q,U,pow[MAXL];
char S[MAXL];

TREE NewNode(TREE f,int v){
    TREE x=new NODE(v);
    x->f=f,x->child[0]=x->child[1]=Null;
    return x;
}

void Initilizer(){
    Null=NewNode(0,0),Null->c=0;
    root=NewNode(Null,0);
    root->child[1]=NewNode(root,0);
}

void Pushup(TREE &x){
    x->c=x->child[0]->c+x->child[1]->c+1;
    x->h=x->child[0]->h+pow[x->child[0]->c]*x->v+pow[x->child[0]->c+1]*x->child[1]->h;
}

void Rotate(TREE &x,bool t){
    TREE y=x->f;
    y->child[!t]=x->child[t],x->child[t]->f=y,x->f=y->f;
    if(y->f->child[0]==y) y->f->child[0]=x;
    else y->f->child[1]=x;
    y->f=x,x->child[t]=y;

    Pushup(y),Pushup(x);
    if(root==y) root=x;
}

void Splay(TREE &x,TREE &y){
    while(x->f!=y)
        if(x->f->f==y)
            if(x->f->child[0]==x) Rotate(x,1);
            else Rotate(x,0);
        else if(x->f->f->child[0]==x->f)
            if(x->f->child[0]==x) Rotate(x->f,1),Rotate(x,1);
            else Rotate(x,0),Rotate(x,1);
        else
            if(x->f->child[0]==x) Rotate(x,1),Rotate(x,0);

            else Rotate(x->f,0),Rotate(x,0);
}

void Build(char *S,int L){
    TREE x,y;
    x=y=NewNode(Null,S[0]-'a'+1);
    for(int i=1;i<L;i++) y=y->child[1]=NewNode(y,S[i]-'a'+1);

    root->child[1]->child[0]=x,x->f=root->child[1];
    Splay(y,Null);
}

void Select(TREE &x,int p){
    TREE y=root;
    while(y->child[0]->c+1!=p)
        if(y->child[0]->c>=p) y=y->child[0];
        else p-=y->child[0]->c+1,y=y->child[1];
    Splay(y,x);
}

int Find(int p,int x){
    Select(Null,p),Select(root,p+x+1);
    Pushup(root->child[1]->child[0]);
    return root->child[1]->child[0]->h;
}

int Query(int x,int y){
    int l=1,r=U-y+1,m=(l+r)>>1;
    while(l<=r){
        if(Find(x,m)==Find(y,m)) l=m+1;
        else r=m-1;
        m=(l+r)>>1;
    }

    if(l>U-y+1 || Find(x,l)!=Find(y,l)) l--;
    return l;
}

void Rewrite(int p,int v){
    Select(Null,p),Select(root,p+2);
    root->child[1]->child[0]->v=v,Pushup(root->child[1]->child[0]);
}

void Insert(int p,int v){
    U++,Select(Null,p+1),Select(root,p+2);
    root->child[1]->child[0]=NewNode(root->child[1],v);
    Pushup(root->child[1]),Pushup(root);
}

int main(){
    Initilizer();
    pow[0]=1;
    for(int i=1;i<=MAXL;i++) pow[i]=pow[i-1]*P;

    scanf("%s",S),U=strlen(S);
    Build(S,U);

    scanf("%d",&Q);
    for(int i=1,x,y;i<=Q;i++){
        scanf("%s %d",S,&x);
        if(S[0]=='Q'){
            scanf("%d",&y);
            printf("%d\n",Query(x,y));
        }
        if(S[0]=='R'){
            scanf("%s",S);
            Rewrite(x,S[0]-'a'+1);
        }
        if(S[0]=='I'){
            scanf("%s",S);
            Insert(x,S[0]-'a'+1);
        }
    }

    return 0;
}
View Code

 

posted @ 2017-02-27 21:58  WDZRMPCBIT  阅读(147)  评论(0编辑  收藏  举报