noip2019集訓測試賽(一)B.字符串

Description

UPD:本題字符集爲全體小寫字母

在這裏插入圖片描述


Input

在這裏插入圖片描述


Output

在這裏插入圖片描述


Solution

這題我寫了一個查詢前暴力get_fail的,複雜度爆炸,但數據水,過了

時間複雜度:O(mlogm)

正解是用所有的s建AC自動機,再建fail樹,最後用樹狀數組維護各種字符串的個數(假的強制在線)。

前序遍歷fail樹,得到dfn,就可以愉快地維護樹狀數組查詢答案了~

關於fail樹可以看看這裏:https://blog.csdn.net/niiick/article/details/87947160

tips:把查詢的s也插入AC自動機其實對解題沒有影響,因爲最後統計的實際是每個操作1和操作2對某段區間的貢獻,即某段區間的點代表的字符串都包含該串。

但是實際上出題人的意思是通過二進制分組,建立logmlogm個AC自動機,使用類似啓發式合併的方法將size相同的AC自動機合併,這樣每個字符串最多被插入logmlogm次,時間複雜度O(mlogm)。(想想就覺得不會打麻煩)


Code

給的是某位AK比賽的學長的代碼,rp++


#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
const int N=2000005;
int m,l,tot=1,len[N],bg[N],fail[N],num[N],ch[N][26];
int cnt,idx,nt,head[N],to[N],nxt[N],dfn[N],siz[N],ck[N];
ll c[N],mask,ans,val[N],op[N];
char s[N],str[N];
void adde(int u,int v){
    to[++cnt]=v;
    nxt[cnt]=head[u];
    head[u]=cnt;
}
void insert(char s[],int id){
    int k=1;
    for(int i=0;i<len[id];i++){
        int x=s[i]-'a';
        if(!ch[k][x]){
            ch[k][x]=++tot;
        }
        k=ch[k][x];
    }
    num[id]=k;
}
void build(){
    queue<int> q;
    q.push(1);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=0;i<26;i++){
            int p=u==1?1:ch[fail[u]][i];
            if(ch[u][i]){
                fail[ch[u][i]]=p;
                q.push(ch[u][i]);
            }else{
                ch[u][i]=p;
            }
        }
    }
    for(int i=2;i<=tot;i++){
        adde(fail[i],i);
    }
}
void dfs(int u){
    dfn[u]=++idx;
    siz[u]=1;
    int v;
    for(int i=head[u];i;i=nxt[i]){
        v=to[i];
        dfs(v);
        siz[u]+=siz[v];
    }
}
void add(int i,int v){
    for(;i<=idx;i+=i&(-i)){
        c[i]+=v;
    }
}
ll query(int i){
    ll res=0;
    for(;i;i-=i&(-i)){
        res+=c[i];
    }
    return res;
}
void go(int l,int r){
    nt++;
    int k=1;
    for(int i=l;i<=r;i++){
        int x=s[i]-'a';
        k=ch[k][x];
        if(cxk[k]==nt){//cxk僅僅用於卡常 CXKNMSL(霧
            ans+=val[k];
        }else{
            cxk[k]=nt;
            val[k]=query(dfn[k]);
            ans+=val[k];
        }
    }
}
int main(){
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%lld%s",&op[i],str);
        len[i]=strlen(str);
        bg[i]=l+1;
        insert(str,i);
        for(int j=0;j<len[i];j++){
            s[++l]=str[j];
        }
    }
    build();
    dfs(1);
    for(int i=1;i<=m;i++){
        op[i]^=mask;
        if(op[i]==1){
            add(dfn[num[i]],1);
            add(dfn[num[i]]+siz[num[i]],-1);
        }else if(op[i]==2){
            add(dfn[num[i]],-1);
            add(dfn[num[i]]+siz[num[i]],1);
        }else{
            ans=0;
            go(bg[i],bg[i]+len[i]-1);
            printf("%lld\n",ans);
            mask^=labs(ans);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章