BZOJ1014: [JSOI2008]火星人prefix

本文介绍了解决BZOJ1014问题的Splay树和Hash算法结合的方法,通过维护Hash值来高效地进行字符串的插入、修改及最长公共前缀查询操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BZOJ1014: [JSOI2008]火星人prefix

Splay·HASH

题解:

一般这种又是插入又是修改的直接上splay啦~
splay维护HASH,求LCP的时候二分一下查HASH是否相等。
复杂度O(Qlog2n)

其实也可以写预先为将来所有可能的位置开点的线段树,原理差不多。

代码比较难写QWQ
肯定是我太弱了。。。

Code:

#include <iostream>
#include <cstring>
#include <cstdio>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define O(x) cout<<x<<" "
#define E cout<<endl
using namespace std;
typedef unsigned long long ull;
const int N = 100005;
const ull BASE = 1e9+7;

ull pow[N]; int n,m; char str[N];

struct Node{
    Node *pa, *ch[2];
    int sz, c; ull hash;
    Node(){ pa=ch[0]=ch[1]=NULL; sz=1; c=0; hash=0; }
    void update();
    void setch(Node*,int);
    int getwh();
} pool[N], *root, *lptr, *rptr;
int ptop=0;

void Node::update(){
    sz=1; if(ch[0]!=NULL)sz+=ch[0]->sz; if(ch[1]!=NULL)sz+=ch[1]->sz;
    hash=0; int lsz=0;
    if(ch[0]!=NULL){ lsz=ch[0]->sz; hash+=ch[0]->hash; }
    hash+=c*pow[lsz];
    if(ch[1]!=NULL){ hash+=ch[1]->hash*pow[lsz+1]; }
}
void Node::setch(Node *child,int wh){
    ch[wh]=child;
    if(child!=NULL) child->pa=this;
    update();
}
int Node::getwh(){
    return pa->ch[0]==this ? 0 : 1;
} 

void dfs(Node *x){
    if(x==NULL) return;
    dfs(x->ch[0]); O(x->c); dfs(x->ch[1]);
}
void dfs(){ puts("dfs:"); dfs(root); E; }

void rotate(Node *x){
    Node *y=x->pa, *z=x->pa->pa; int wh=x->getwh();
    y->setch(x->ch[wh^1],wh); x->setch(y,wh^1);
    x->pa=z; if(z!=NULL) z->ch[z->ch[0]==y?0:1]=x;
}
void splay(Node *x,Node *tar){
    if(x==tar) return;
    for(; x->pa!=tar; rotate(x)) if(x->pa->pa!=tar)
        x->getwh()==x->pa->getwh() ? rotate(x->pa) : rotate(x);
    if(tar==NULL) root=x;
}

Node* find(int pos){
    Node *now=root; int lsz=0;
    while(now!=NULL){
        int tp; if(now->ch[0]!=NULL)tp=now->ch[0]->sz+1; else tp=1;
        if(lsz+tp < pos){ lsz+=tp; now=now->ch[1]; }
        else if(lsz+tp > pos){ now=now->ch[0]; }
        else{ return now; }
    }
    return NULL;
}
void insert(int pos,int c){
//  puts("insert:"); D(pos); D(c); E;
    Node *newone = &pool[ptop++]; newone->c=c;
    Node *x=find(pos); Node *y=find(pos+1);
//  D(x->c); D(y->c); E;
    splay(x,NULL); splay(y,x); newone->setch(y,1); x->setch(newone,1);
}
void change(int pos,int c){
    Node *x=find(pos);
    x->c=c; splay(x,NULL);
}

ull getHash(int l,int r){
    Node *x=find(l-1); Node *y=find(r+1);
    splay(x,NULL); splay(y,x);
    return y->ch[0]->hash;
}
int solve(int a,int b){
    int l=0,r=n-(max(a,b)-1)+1,mid;
    while(l<r){
        mid=l+(r-l+1)/2;
        if(getHash(a,a+mid-1) == getHash(b,b+mid-1)) l=mid;
        else r=mid-1;
    }
    return l;
}

void init(){
    pow[0]=1; for(int i=1;i<=100000;i++) pow[i]=pow[i-1]*BASE;
    ptop=0;
    lptr=&pool[ptop++]; lptr->c=-1; root=lptr; 
    rptr=&pool[ptop++]; rptr->c=-2; lptr->setch(rptr,1);
}

int main(){
    freopen("a.in","r",stdin);
    scanf("%s",str); n=strlen(str);
    init();
    for(int i=1;i<=n;i++) insert(i,str[i-1]-'a'+1);
//  dfs();
    scanf("%d",&m); int a,b; char op[5];
    for(int i=1;i<=m;i++){
//      D(i); E;
        scanf("%s",op);
        if(op[0]=='Q'){
            scanf("%d%d",&a,&b); a++; b++;
            printf("%d\n",solve(a,b));
        }
        else if(op[0]=='R'){
            scanf("%d%s",&a,str); a++;
            change(a,str[0]-'a'+1);
        }
        else if(op[0]=='I'){
            scanf("%d%s",&a,str); a++; n++;
            insert(a,str[0]-'a'+1);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值