loj #6070. 「2017 山东一轮集训 Day4」基因

回文自动机好题啊!

解法一

每$\sqrt n \(分一块 每块建回文自动机到字符串末尾。 顺便开三个\)\sqrt n *n \(的数组记下预处理答案,回文自动机头指针,和每个节点第一次出现的右端点 询问的时候回文自动机前端添加,算出答案。 貌似不能写均摊复杂度的回文自动机,只能写单次复杂度有证明的。 设\)T\(为字符集大小 时间复杂度\)O(Tn \sqrt n)$

#include <bits/stdc++.h>
using namespace std;
const int N=100010,D=320;
int pre[D][N],preworkans[D][N],firstappear[D][N],vis[N];
struct pam{
    struct pamnode{
        int len,fa,anc[26],trans[26];
    }T[N];
    int tot,fi,la;
    pam(){
        T[1].len=-1;
        T[0].fa=1;
        for (int j=0; j<26; ++j) T[0].anc[j]=1;
        tot=1;
        fi=0;
        la=0;
    }
    void pushback(char *s,int l,int r){
        int c=s[r]-'a';
        if (r-T[la].len-1<l||s[r]!=s[r-T[la].len-1]) la=T[la].anc[c];
        if (!T[la].trans[c]){
            int q=++tot,k=T[la].fa;
            T[q].len=T[la].len+2;
            if (r-T[k].len-1<l||s[r]!=s[r-T[k].len-1]) T[q].fa=T[T[k].anc[c]].trans[c];
            else T[q].fa=T[k].trans[c];
            memcpy(T[q].anc,T[T[q].fa].anc,sizeof(T[q].anc));
            T[q].anc[s[r-T[T[q].fa].len]-'a']=T[q].fa;
            T[la].trans[c]=q;
        }
        la=T[la].trans[c];
        if (T[la].len==r-l+1) fi=la;
    }
    void pushfront(char *s,int l,int r){
        int c=s[l]-'a';
        if (l+T[fi].len+1>r||s[l]!=s[l+T[fi].len+1]) fi=T[fi].anc[c];
        if (!T[fi].trans[c]){
            int q=++tot,k=T[fi].fa;
            T[q].len=T[fi].len+2;
            if (l+T[k].len+1>r||s[l]!=s[l+T[k].len+1]) T[q].fa=T[T[k].anc[c]].trans[c];
            else T[q].fa=T[k].trans[c];
            memcpy(T[q].anc,T[T[q].fa].anc,sizeof(T[q].anc));
            T[q].anc[s[l+T[T[q].fa].len]-'a']=T[q].fa;
            T[fi].trans[c]=q;
        }
        fi=T[fi].trans[c];
        if (T[fi].len==r-l+1) la=fi;
    }
}A;
int ty,n,q,S,clk,ans;
char s[N];
int main(){
    scanf("%d%d%d%s",&ty,&n,&q,s+1);
    S=sqrt(n);
    for (int i=0; i*S+1<=n; ++i){
        A.fi=A.la=0; ++clk;
        for (int j=i*S+1; j<=n; ++j){
            A.pushback(s,i*S+1,j);
            preworkans[i][j]=preworkans[i][j-1];
            if (vis[A.la]<clk){
                vis[A.la]=clk;
                firstappear[i][A.la]=j;
                ++preworkans[i][j];
            }
            pre[i][j]=A.fi;
        }
    }
    while (q--){
        int l,r;
        scanf("%d%d",&l,&r);
        l^=(ty*ans);
        r^=(ty*ans);
        ++clk;
        if ((l-1)/S==(r-1)/S){
            A.fi=A.la=0;
            ans=0;
            for (int i=l; i<=r; ++i){
                A.pushback(s,l,i);
                if (vis[A.la]<clk){
                    vis[A.la]=clk;
                    ++ans;
                }
            }
        }
        else{
            int L=(l-1)/S+1-(l%S==1);
            A.fi=pre[L][r];
            ans=preworkans[L][r];
            for (int i=L*S; i>=l; --i){
                A.pushfront(s,i,r);
                if (vis[A.fi]<clk){
                    vis[A.fi]=clk;
                    if (firstappear[L][A.fi]>r||firstappear[L][A.fi]==0) ++ans;
                }
            }
        }
        cout<<ans<<'\n';
    }
}

解法2

记回文自动机上一个节点的串长为\(len(x)\),父节点为\(fa(x)\),则对于回文树上一条链,从叶子到根,\(len(x)-len(fa(x))\)递减,且只有\(log\)种取值,也就是说,可以分成\(log\)个等差数列。
主席树维护扫描右端点时左端点的答案,一个等差数列就是一个区间加。
时间复杂度\(O(nlog^2(n))\)

#include <bits/stdc++.h>
using namespace std;
#define debug(x) cerr<<#x<<":"<<x<<endl
const int N=100010;
const int P=270010;
const int D=17*17*N;
struct zkw{
    int u,st[P];
    void init(int len){
        for (u=1; u<len; u<<=1); 
        --u;
    }
    void mark(int s,int t){
        //cerr<<"Mark"<<s<<" "<<t<<endl;
        for (s+=u; s; s>>=1) st[s]=max(st[s],t);
    }
    int ask(int s,int t){
        //cerr<<"ask"<<s<<" "<<t<<endl;
        int ret=0;
        for (s+=u-1,t+=u+1; s^t^1; s>>=1,t>>=1){
            if (~s&1) ret=max(ret,st[s^1]);
            if (t&1) ret=max(ret,st[t^1]);
        }
        //debug(ret);
        return ret;
    }
}seg1;
struct president{
    int ll,rr,tot;
    struct presidentnode{
        int l,r,v;
    }T[D];
    void add(int &ind,int l,int r){
        /*if (l!=13||r!=12){
        debug(l); debug(r); debug(tot);
        debug(ll); debug(rr);
        }*/ 
        T[++tot]=T[ind];
        ind=tot;
        //cerr<<"CC"<<endl;
        if (ll<=l&&r<=rr) return void(++T[ind].v);
        int mid=(l+r)>>1;
        if (ll<=mid) add(T[ind].l,l,mid);
        if (mid<rr) add(T[ind].r,mid+1,r);
    }
    int ask(int ind,int l,int r){
        if (l==r) return T[ind].v;
        int mid=(l+r)>>1;
        return (ll<=mid?ask(T[ind].l,l,mid):ask(T[ind].r,mid+1,r))+T[ind].v;
    }
}seg2;
struct pam{
    vector<int> g[N];
    struct pamnode{
        int fa,len,d,df,trans[26];
    }T[N];
    int la,tot,dfn[N],clk,lst[N];
    pam(){
        T[1].len=-1;
        T[0].fa=1;
        T[0].d=-1;
        tot=1;
        la=0;
    }
    int pushback(char *s,int l,int r){
        int c=s[r]-'a';
        while (r-T[la].len-1<l||s[r]!=s[r-T[la].len-1]) la=T[la].fa;
        if (!T[la].trans[c]){
            int q=++tot,k=T[la].fa;
            T[q].len=T[la].len+2;
            while (r-T[k].len-1<l||s[r]!=s[r-T[k].len-1]) k=T[k].fa;
            T[q].fa=T[k].trans[c];
            T[la].trans[c]=q;
            T[q].d=(T[q].fa?T[q].len-T[T[q].fa].len:0);
            T[q].df=(T[q].d==T[T[q].fa].d?T[T[q].fa].df:q);
        }
        return la=T[la].trans[c];
    }
    void dfs(int x){
        //debug(x); debug(fa);
        dfn[x]=clk++;
        for (auto i:g[x]) dfs(i);
        lst[x]=clk-1;
    }
    void prework(){
        for (int i=tot; i>1; --i) g[T[i].fa].push_back(i);
        dfs(0);
    }
}A;
int ty,n,q,ans,rt[N],rec[N];
char s[N];
void build(){
    //for (int i=1; i<=A.tot; ++i) debug(A.dfn[i]);
    seg1.init(A.tot);
    for (int i=1; i<=n; ++i){
        rt[i]=rt[i-1];
        int x=rec[i];
        while (x>1){
            seg2.ll=max(seg1.ask(A.dfn[x],A.lst[x])-A.T[x].len+2,1);
            seg2.rr=i-A.T[A.T[x].df].len+1;
            //cerr<<"plus"<<i<<" "<<seg2.ll<<" "<<seg2.rr<<" "<<A.T[x].df<<" "<<A.T[x].len<<endl;
            seg2.add(rt[i],1,n);
            x=A.T[A.T[x].df].fa;
        }
        seg1.mark(A.dfn[rec[i]],i);
    }
}
int main(){
    scanf("%d%d%d%s",&ty,&n,&q,s+1);
    for (int i=1; i<=n; ++i) rec[i]=A.pushback(s,1,i)/*,debug(rec[i]),debug(A.T[rec[i]].fa)*/;
    A.prework();
    build();
    while (q--){
        int l,r;
        scanf("%d%d",&l,&r);
        l^=(ty*ans);
        r^=(ty*ans);
        seg2.ll=l;
        cout<<(ans=seg2.ask(rt[r],1,n))<<'\n';
    }
}

猜你喜欢

转载自www.cnblogs.com/Yuhuger/p/10073798.html