[bzoj2555]SubString

2555: SubString

Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 1374 Solved: 410
[Submit][Status][Discuss]
Description

懶得寫背景了,給你一個字符串init,要求你支持兩個操作

(1):在當前字符串的後面插入一個字符串

(2):詢問字符串s在當前字符串中出現了幾次?(作爲連續子串)

你必須在線支持這些操作。

Input

第一行一個數Q表示操作個數

第二行一個字符串表示初始字符串init

接下來Q行,每行2個字符串Type,Str 

Type是ADD的話表示在後面插入字符串。

Type是QUERY的話表示詢問某字符串在當前字符串中出現了幾次。

爲了體現在線操作,你需要維護一個變量mask,初始值爲0

這裏寫圖片描述

讀入串Str之後,使用這個過程將之解碼成真正詢問的串TrueStr。
詢問的時候,對TrueStr詢問後輸出一行答案Result
然後mask = mask xor Result  
插入的時候,將TrueStr插到當前字符串後面即可。

HINT:ADD和QUERY操作的字符串都需要解壓

Output

Sample Input

2



A



QUERY B



ADD BBABBBBAAB

Sample Output

0

HINT

40 % 的數據字符串最終長度 <= 20000,詢問次數<= 1000,詢問總長度<= 10000
100 % 的數據字符串最終長度 <= 600000,詢問次數<= 10000,詢問總長度<= 3000000

網上的題解都寫的是SAM+LCT ,但是可以用後綴平衡樹來做。
後綴平衡樹就是一個可以維護後綴字典序大小關係的平衡樹。也就是後綴數組中的sa 數組。
對於這道題來說,因爲每次需要在最後加一個字符串,所以可以將字符串倒過來,這樣就相當於每次加入一些後綴。每次把這個後綴插入到平衡樹中去。每走到一個節點,需要比較字典序的大小,這裏就可以用另一種求lcp 的方法:二分+hash
查詢的時候可以在在查詢的字符串後加一個很小的字符,查一次排名,刪掉小的再加一個大的查一次,兩次的排名相減就是答案。爲了方便寫平衡樹裏的比較函數,我每次查詢的時候都先把這個串接到原串的後面,查完之後再刪掉。
時間複雜度:O(nlog2n)
但是這個題剛寫完一直T 的飛起,搞了好久才A
①:平衡樹一定要開內存池,每次new 非常慢。
②:這道題用unsigned int 就行,不需要unsigned long long
③:在每次二分的時候,可以加一點優化:可以先看一下前x 位的hash 值是否相同,如果不同的話就把二分上限設成x (我這裏的x 取得是25 )。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
#define LL unsigned int
#define p 233LL
#define mid (l+r)/2
const int N=4000010;
char s[N],ss[N];
int T,n,ans,flag,mask,cnt,tp;
LL hash[N],pow[N];
struct Node{
    LL v;
    Node *ch[2];
    int r,num,sum,len,No;
    inline int cmp(LL x,int now,int Len){
        int l=1,r=min(len,Len),maxn=0;
        if(!flag) r=min(r,Len-n);
        if(r>25){
            LL o0=v-((No-25)<0?0:hash[No-25]*pow[25]);
            LL o1=x-((now-25)<0?0:hash[now-25]*pow[25]);
            if(o0!=o1) r=25;
            else l=maxn=25;
        }
        while(l<=r){
            LL o0=v-((No-mid)<0?0:hash[No-mid]*pow[mid]);
            LL o1=x-((now-mid)<0?0:hash[now-mid]*pow[mid]);
            if(o0==o1) maxn=max(maxn,mid),l=mid+1;
            else r=mid-1;
        }
        if(!flag){
            if(maxn==Len-n-1){
                if(s[Len-maxn-1]==(char)1) return 0;
                else return 1;      
            } 
        }
        if(maxn==Len) return Len==len?-1:0;
        if(maxn==len) return Len==len?-1:1;
        return s[No-maxn]<s[now-maxn]?1:0;
    }
    inline void Maintain(){
        sum=num;
        if(ch[0]!=NULL) sum+=ch[0]->sum;
        if(ch[1]!=NULL) sum+=ch[1]->sum;
    }
}*root,pool[N];
inline void rotate(Node* &o,int d){
    Node* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
    o->Maintain();k->Maintain();o=k;
}
inline void insert(Node* &o,LL x,int now,int kind,int Len){
    if(o==NULL){
        o=&pool[++tp];
        o->ch[0]=o->ch[1]=NULL;
        o->r=rand();
        o->num=1;
        o->v=x;
        o->len=Len;
        o->No=now;
    }
    else{
        int d=o->cmp(x,now,Len);
        if(d==-1) o->num+=1;
        else{
            insert(o->ch[d],x,now,kind,Len);
            if(o->r < o->ch[d]->r) rotate(o,d^1);
        }
    }
    o->Maintain();
}
inline int rank(Node* &o,LL x,int now,int Len){
    if(o==NULL) return 0;
    int d=o->cmp(x,now,Len);
    if(d==-1) return (o->ch[0]==NULL?1:o->ch[0]->sum+1);
    else{
        if(d==0) return rank(o->ch[0],x,now,Len);
        else return (rank(o->ch[1],x,now,Len)+(o->ch[0]==NULL?o->num:o->ch[0]->sum+o->num));
    }
}
inline void in(int kind){
    flag=kind;++cnt;
    int now=0,i,pre=mask;
    char ch=getchar();
    while(ch<'A'||ch>'Z') ch=getchar();
    while(ch>='A'&&ch<='Z'){
        //s[n]=ch;
        ss[now]=ch;
        //pow[n]=n?(pow[n-1]*p):1LL;
        //hash[n]=(n?(hash[n-1]*p):0LL)+(LL)s[n];
        //if(kind) insert(root,hash[n],n,kind,n+1);
        ++now,ch=getchar();
    }
    for(i=0;i<now;++i){
        if(cnt==1) continue;
        mask=(mask*131+i)%now;
        char t=ss[i];
        ss[i]=ss[mask];
        ss[mask]=t;
    }
    for(i=0;i<now;++i){
        s[n]=ss[i];
        pow[n]=n?(pow[n-1]*p):1LL;
        hash[n]=(n?(hash[n-1]*p):0LL)+(LL)s[n];
        if(kind) insert(root,hash[n],n,kind,n+1);
        ++n;
    }
    mask=pre;
    if(!kind){
        n-=now;
        pow[n]=pow[n-1]*p;
        hash[n]=hash[n-1]*p+1LL;
        for(i=now-1;~i;--i) s[i+n+1]=s[i+n];
        for(s[n]=(char)1,i=n+1;i<=n+now;++i)
          pow[i]=pow[i-1]*p,hash[i]=hash[i-1]*p+(LL)s[i];
        ans=-rank(root,hash[n+now],now+n,now+n+1);
        hash[n]=hash[n-1]*p+126LL;
        for(s[n]=(char)126,i=n+1;i<=n+now;++i)
          pow[i]=pow[i-1]*p,hash[i]=hash[i-1]*p+(LL)s[i];
        ans+=rank(root,hash[n+now],now+n,now+n+1);
        for(i=0;i<now;++i) s[n+i]=s[n+i+1];
        mask^=ans;
        printf("%d\n",ans);
    }
}
int main(){
    int i,j;
    scanf("%d",&T);
    s[0]=(char)1;
    in(1);
    while(T--){
        char o[10],ch=getchar(),len=0;
        while(ch<'A'||ch>'Z') ch=getchar();
        while(ch>='A'&&ch<='Z') o[len++]=ch,ch=getchar();
        if(o[0]=='Q') in(0);
        else in(1);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章