zoukankan      html  css  js  c++  java
  • bzoj2555 LCT维护后缀自动机

    通过用LCT维护parent树来实现后缀自动机的在线操作。

    注意right值初始化为0,然后加新结点的时候只要将np的right值设为1,而不需要改变nq的right值,因为nq是内部的结点,np才是外层的结点。

    思路很简单,代码真长,调了挺久。。。。不过写起来还算清晰。。。

    #include<bits/stdc++.h>
    #define REP(i,a,b) for(int i=a;i<=b;i++)
    #define MS0(a) memset(a,0,sizeof(a))
    
    using namespace std;
    
    typedef long long ll;
    const int maxn=3200100;
    const int INF=1e9+10;
    
    char s[maxn];
    int len;
    char op[20];
    int Q;
    
    struct LCT
    {
        int pre[maxn],ch[maxn][2],rev[maxn];
        int val[maxn],add[maxn];
        void init()
        {
            MS0(pre);MS0(ch);MS0(rev);MS0(add);
            MS0(val);
        }
        void update_add(int x,int w)
        {
            if(!x) return;
            val[x]+=w;
            add[x]+=w;
        }
        void update_rev(int x)
        {
            if(!x) return;
            swap(ch[x][0],ch[x][1]);
            rev[x]^=1;
        }
        void down(int x)
        {
            if(add[x]){
                update_add(ch[x][0],add[x]);
                update_add(ch[x][1],add[x]);
                add[x]=0;
            }
            if(rev[x]){
                update_rev(ch[x][0]);
                update_rev(ch[x][1]);
                rev[x]=0;
            }
        }
        bool isroot(int x)
        {
            return ch[pre[x]][0]!=x&&ch[pre[x]][1]!=x;
        }
        void up(int x)
        {
    
        }
        void P(int x)
        {
            if(!isroot(x)) P(pre[x]);
            down(x);
        }
        void rot(int x,int kind)
        {
            int y=pre[x];
            ch[y][kind^1]=ch[x][kind];
            pre[ch[x][kind]]=y;
            if(!isroot(y)) ch[pre[y]][ch[pre[y]][1]==y]=x;
            pre[x]=pre[y];
            ch[x][kind]=y;
            pre[y]=x;
            up(y);
        }
        void splay(int x)
        {
            P(x);
            while(!isroot(x)){
                if(isroot(pre[x])) rot(x,ch[pre[x]][0]==x);
                else{
                    int y=pre[x],z=pre[y];
                    int kind=ch[y][0]==x,one=0;
                    if(ch[y][0]==x&&ch[z][0]==y) one=1;
                    if(ch[y][1]==x&&ch[z][1]==y) one=1;
                    if(one) rot(y,kind),rot(x,kind);
                    else rot(x,kind),rot(x,kind^1);
                }
            }
            up(x);
        }
        int access(int x)
        {
            int t=0;
            while(x){
                splay(x);
                ch[x][1]=t;t=x;x=pre[x];
                up(t);
            }
            return t;
        }
        void makeroot(int x)
        {
            access(x);splay(x);update_rev(x);
        }
        void ADD(int x,int y,int w)
        {
            makeroot(x);access(y);splay(y);
            update_add(y,w);
        }
        void cut(int x,int y)
        {
            makeroot(x);access(y);splay(y);ch[y][0]=pre[x]=0;up(y);
            ADD(y,1,-val[x]);
        }
        void link(int x,int y)
        {
            makeroot(x);pre[x]=y;up(y);
            ADD(y,1,val[x]);
        }
        int query(int x)
        {
            splay(x);
            return val[x];
        }
    };LCT lct;
    
    struct SAM
    {
        int ch[maxn][26];
        int pre[maxn],step[maxn];
        int last,tot;
        int newnode(int k)
        {
            ++tot;
            step[tot]=k;
            MS0(ch[tot]);
            pre[tot]=0;
            return tot;
        }
        void init()
        {
            tot=0;
            last=newnode(0);
            lct.init();
        }
        void add(int c)
        {
            c-='A';
            int p=last,np=newnode(step[p]+1);
            lct.val[np]=1;
            while(p&&ch[p][c]==0) ch[p][c]=np,p=pre[p];
            if(p==0) pre[np]=1,lct.link(np,1);
            else{
                int q=ch[p][c];
                if(step[q]!=step[p]+1){
                    int nq=newnode(step[p]+1);
                    memcpy(ch[nq],ch[q],sizeof(ch[q]));
                    lct.cut(q,pre[q]);
                    lct.link(nq,pre[q]);
                    lct.link(q,nq);
                    lct.link(np,nq);
                    pre[nq]=pre[q];
                    pre[q]=pre[np]=nq;
                    while(p&&ch[p][c]==q) ch[p][c]=nq,p=pre[p];
                }
                else pre[np]=q,lct.link(np,q);
            }
            last=np;
        }
        int find(char *s)
        {
            int len=strlen(s);
            int u=1;
            REP(i,0,len-1){
                int c=s[i]-'A';
                if(ch[u][c]) u=ch[u][c];
                else return 0;
            }
            return lct.query(u);
        }
    };SAM sam;
    
    void decode(char *s,int mask)
    {
        int len=strlen(s);
        REP(i,0,len-1){
            mask=(mask*131+i)%len;
            swap(s[i],s[mask]);
        }
    }
    
    int main()
    {
        freopen("in.txt","r",stdin);
        while(~scanf("%d",&Q)){
            scanf("%s",s);
            len=strlen(s);
            sam.init();
            REP(i,0,len-1) sam.add(s[i]);
            int mask=0;
            REP(i,1,Q){
                scanf("%s%s",op,s);
                decode(s,mask);
                if(op[0]=='A'){
                    len=strlen(s);
                    REP(i,0,len-1) sam.add(s[i]);
                }
                else{
                    int res=sam.find(s);
                    printf("%d
    ",res);
                    mask^=res;
                }
            }
        }
        return 0;
    }
    View Code
    没有AC不了的题,只有不努力的ACMER!
  • 相关阅读:
    关于token的理解
    JavaScript 中 call()、apply()、bind() 的用法
    常用JS整理
    js里面for循环的++i与i++
    前端命名规范
    H5混合开发app常用代码
    jquery知识巩固
    水平垂直居中(固定宽不固定宽)
    css3新属性运用
    bug笔记(pc)
  • 原文地址:https://www.cnblogs.com/--560/p/5462859.html
Copyright © 2011-2022 走看看