BZOJ 1014 [JSOI2008]火星人prefix

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

 

这题三个操作:

  1.询问

  2.修改

  3.添加

 

因为这是一个序列,同时需要进行三种操作,还要支持添加,所以会想到平衡树这种数据结构。

每棵子树表示一段序列,树上的每个节点储存这棵子树的信息以及这个点在序列中的具体的单点信息。

但是这题的询问有点麻烦,因为是询问后缀是否相等,可是操作后缀对于平衡树来还是有些麻烦,所以需要的是二分答案,来找到一截一截的比较。

关于一截一截的比较,平衡树已经多次运用了[其实就是闭合区间的询问嘛]。

但是如何判断两截相等呢?这里利用的就是Hash了,字符串Hash中有种比较好用的就是转成26进制数。

但是这题中有不同在于定了虚拟节点,这虚拟节点的Hash值等于0的话就会和'a'相同了[大概只是我的猜测,因为我这样WA了几次],保险起见转成27进制可能会好些。

 

具体操作:

操作1[询问]:二分答案再询问两段序列是否相等,询问时将区间在树中找出,返回其Hash值判断是否相等。

操作2[修改]:将需要修改的点转到顶上修改即可[这样就不会影响其它节点了]

操作3[添加]:将需要添加的位置在树中标示,然后直接加入即可。

 

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

inline int in(){
    int x=0;char ch=getchar();
    while(ch>'9' || ch<'0') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}

const int maxn=101000;
const int mod=9875321;

typedef long long ll;

struct Node{
    int sz;
    int l,r,f;
    int hx,cr;
}s[maxn];

int len,rt,cnt;
int p[maxn];
int nch[maxn];
char ch[maxn];

void update(int x){
    int l=s[x].l,r=s[x].r;
    s[x].sz=s[l].sz+s[r].sz+1;
    s[x].hx=s[l].hx+(ll)s[x].cr*p[s[l].sz]%mod+(ll)p[s[l].sz+1]*s[r].hx%mod;
    s[x].hx%=mod;
}

int build(int l,int r){
    if(l>r) return 0;
    int mid=(l+r)>>1;
    s[mid].cr=nch[mid-1];
    s[mid].l=build(l,mid-1);
    s[mid].r=build(mid+1,r);
    if(s[mid].l) s[s[mid].l].f=mid;
    if(s[mid].r) s[s[mid].r].f=mid;
    update(mid);
    return mid;
}

void zig(int x){
    int y=s[x].f;
    s[x].f=s[y].f;
    if(s[y].f){    
        if(y==s[s[y].f].l) s[s[y].f].l=x;
        else s[s[y].f].r=x;
    }
    s[y].l=s[x].r;
    if(s[x].r)
        s[s[x].r].f=y;
    s[y].f=x,s[x].r=y;
    update(y);update(x);
}

void zag(int x){
    int y=s[x].f;
    s[x].f=s[y].f;
    if(s[y].f){    
        if(y==s[s[y].f].l) s[s[y].f].l=x;
        else s[s[y].f].r=x;
    }
    s[y].r=s[x].l;
    if(s[x].l)
        s[s[x].l].f=y;
    s[x].l=y,s[y].f=x;
    update(y);update(x);
}

void Splay(int x,int gf){
    int y;
    while(s[x].f!=gf){
        y=s[x].f;
        if(s[y].f==gf){
            if(x==(s[y].l)) zig(x);
            else zag(x);
        }
        else{
            int z=s[y].f;
            if(y==s[z].l){
                if(x==s[y].l) zig(y),zig(x);
                else zag(x),zig(x);
            }
            else{
                if(x==s[y].r) zag(y),zag(x);
                else zig(x),zag(x);
            }
        }
    }
    if(!gf) rt=x;
}

int Find(int k){
    int p=rt;
    if(k>s[p].sz) return 0;
    while(p){
        if(k<=s[s[p].l].sz) p=s[p].l;
        else{
            k-=s[s[p].l].sz;
            if(k==1) return p;
            k--;p=s[p].r;
        }
    }
}

void change(int x,char c){
    int a=Find(x+1);
    Splay(a,0);
    s[a].cr=c-'a'+1;
    update(a);
}

void add(int x,char c){
    int a=Find(x+1),b=Find(x+2);
    Splay(a,0);Splay(b,a);
    s[b].l=++cnt;
    s[cnt].f=b;
    s[cnt].cr=c-'a'+1;
    update(cnt),update(b),update(a);
}

int get_h(int l,int r){
    int a=Find(l),b=Find(r+2);
    Splay(a,0);Splay(b,a);
    return s[s[b].l].hx;
}

int ask(int i,int j){
    int mid,l=0,r=min(cnt-j,cnt-i);
    while(r-l>1){
        mid=(l+r)>>1;
        if(get_h(i,i+mid-1)==get_h(j,j+mid-1)) l=mid;
        else r=mid;
    }
    return l;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("1014.in","r",stdin);
    freopen("1014.out","w",stdout);
#endif
    
    char ord,col;
    int l,r;
    
    scanf("%s",ch+1);
    len=strlen(ch+1);
    p[0]=1;
    for(int i=1;i<maxn;i++) p[i]=p[i-1]*27%mod;
    for(int i=1;i<=len;i++) nch[i]=ch[i]-'a'+1;
    rt=build(1,len+2);cnt=len+2;
    
    int m=in();
    while(m--){
        scanf("\n%c",&ord);
        if(ord=='Q'){
            l=in(),r=in();
            printf("%d\n",ask(l,r));
        }
        else if(ord=='R'){
            l=in();scanf("%c",&col);
            change(l,col);
        }
        else{
            l=in();scanf("%c",&col);
            add(l,col);
        }
    }
    
    return 0;
}
View Code

 

posted @ 2015-12-26 09:31  诚叙  阅读(182)  评论(0编辑  收藏  举报