zoukankan      html  css  js  c++  java
  • bzoj 2555: SubString 后缀自动机+LCT

    2555: SubString

    Time Limit: 30 Sec  Memory Limit: 512 MB
    Submit: 688  Solved: 235
    [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


    新加数据一组--2015.05.20

      5月20日,新加数据一组,今天5月21号。我选时间怎么就选的这么优秀。还对着一堆比我慢的程序调了半天的常数。。。

      第一次做这类维护right集合大小的题目,right集合大小即子树有用节点的数量,有用节点即不是复制出来的节点。

      在昨天以前这个直接暴力维护暴力链加,修改父亲,然而现在就只有LCT了。另外,为啥不全部重测QAQ,不平衡啊。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    using namespace std;
    #define MAXN 1210000
    int pnt[MAXN],ch[MAXN][2],pls[MAXN],val[MAXN];
    bool rev[MAXN];
    int stack[MAXN],tops=-1;
    bool is_root(int now)
    {
            return !pnt[now] || (ch[pnt[now]][0]!=now && ch[pnt[now]][1]!=now);
    }
    void update(int){}
    void make_reverse(int now)
    {
            swap(ch[now][0],ch[now][1]);
            rev[now]^=1;
    }
    void make_plus(int now,int v)
    {
            val[now]+=v;
            pls[now]+=v;
    }
    void down(int now)
    {
            if (rev[now])
            {
                    make_reverse(ch[now][0]);
                    make_reverse(ch[now][1]);
                    rev[now]=0;
            }
            if (pls[now])
            {
                    make_plus(ch[now][0],pls[now]);
                    make_plus(ch[now][1],pls[now]);
                    pls[now]=0;
            }
    }
    void rotate(int now)
    {
            int p=pnt[now],anc=pnt[p];
            int dir=ch[p][0]==now;
            if (!is_root(p))
                    ch[anc][ch[anc][1]==p]=now;
            pnt[now]=anc;
            pnt[ch[now][dir]]=p;
            ch[p][1-dir]=ch[now][dir];
            pnt[p]=now;
            ch[now][dir]=p;
            update(p);
            update(now);
    }
    
    void splay(int now)
    {
            int x=now;
            stack[++tops]=now;
            while (!is_root(x))
            {
                    x=pnt[x];
                    stack[++tops]=x;
            }
            while(~tops)
                    down(stack[tops--]);
            while (!is_root(now))
            {
                    int p=pnt[now],anc=pnt[p];
                    if (is_root(p))
                            rotate(now);
                    else if ((ch[anc][0]==p) == (ch[p][0]==now))
                            rotate(p),rotate(now);
                    else
                            rotate(now),rotate(now);
            }
    }
    int access(int now)
    {
            int son=0;
            while (now)
            {
                    splay(now);
                    ch[now][1]=son;
                    update(now);
                    son=now;
                    now=pnt[now];
            }
            return son;
    }
    bool same_tree(int x,int y)
    {
            while (pnt[x])x=pnt[x];
            while (pnt[y])y=pnt[y];
            return x==y;
    }
    void make_root(int now)
    {
            make_reverse(access(now));
    }
    void path_plus(int x,int y,int v)
    {
            //cout<<"Plus:"<<x<<" "<<y<<endl;
            assert(same_tree(x,y));
            make_root(x);
            make_plus(access(y),v);
    }
    void link(int x,int y)
    {
            //cout<<"Link:"<<x<<" "<<y<<endl;
            assert(!same_tree(x,y));
            make_root(x),access(x);
            make_root(y),access(y);
            pnt[x]=y;
            ch[y][1]=x;
    }
    void cut(int x,int y)
    {
            //cout<<"Cut:"<<x<<" "<<y<<endl;
            assert(same_tree(x,y));
            make_root(x);
            access(y);
            ch[x][1]=0;
            pnt[y]=0;
    }
    char str[MAXN],ss[MAXN];
    struct sam_node
    {
            int nxt[26];
            int pnt;
            int len;
    }sam[MAXN];
    int topsam=1;
    int last=1;
    void Add_sam(char ch)
    {
            register int p=last;
            register int np=++topsam;
            sam[np].len=sam[p].len+1;
            val[np]=1;
            while (p && !sam[p].nxt[ch-'A'])
            {
                    sam[p].nxt[ch-'A']=np;
                    p=sam[p].pnt;
            }
            if (!p)
            {
                    last=np;
                    sam[np].pnt=1;
                    link(np,sam[np].pnt);
            }else
            {
                    register int q=sam[p].nxt[ch-'A'];
                    if (sam[q].len==sam[p].len+1)
                    {
                            sam[np].pnt=q;
                            link(sam[np].pnt,np);
                            last=np;
                    }else
                    {
                            register int nq=++topsam;
                            splay(q);
                            val[nq]=val[q];
                            sam[nq]=sam[q];
                            link(sam[nq].pnt,nq);
                            sam[nq].len=sam[p].len+1;
                            cut(sam[q].pnt,q);
                            /*ooo*/sam[q].pnt=nq;
                            link(sam[q].pnt,q);
                            /*ooo*/sam[np].pnt=nq;
                            link(sam[np].pnt,np);
                            while (p && sam[p].nxt[ch-'A']==q)
                            {
                                    sam[p].nxt[ch-'A']=nq;
                                    p=sam[p].pnt;
                            }
                            last=np;
                    }
            }
            path_plus(1,sam[np].pnt,1);
    }
    char curs[MAXN];int totc=0;
    /*
       void dfs_sam(int now)
       {
       if (sam[now].flag)
       printf("%s
    ",curs);
       for (int i=0;i<26;i++)
       {
       if (!sam[now].nxt[i])continue;
       curs[totc++]=(char)(i+'A');
       dfs_sam(sam[now].nxt[i]);
       curs[--totc]='';
       }
       }*/
    int find_sam(char *str)
    {
            int now=1;
            while (*str)
            {
                    if (!sam[now].nxt[*str-'A'])return 0;
                    assert(sam[now].nxt[*str-'A']);
                    now=sam[now].nxt[*str-'A'];
                    str++;
            }
            make_root(now);
            access(now);
            return val[now];
    }
    void Decode(char* str,int len,int mask)
    {
            for (register int i=0;i<len;i++)
            {
                    mask=(mask*131+i)%len;
                    swap(str[i],str[mask]);
            }
    }
    char opt[20];
    char cc[MAXN];
    int main()
    {
            freopen("input.txt","r",stdin);
            int n,m,x,y,z;
            scanf("%d
    ",&m);
            scanf("%s",str);
            int l=strlen(str);
            for (int i=0;i<l;i++)
                    Add_sam(str[i]);
            /*
               for (int i=last;i;i=sam[i].pnt)sam[i].flag=true;
               dfs_sam(1);
               for (int i=0;i<l;i++)find_sam(str+i);*/
            int lastans=0;
            for (int i=0;i<m;i++)
            {
                    scanf("%s %s
    ",opt,cc);
                    int t;
                    t=strlen(cc);
                    Decode(cc,t,lastans);
                    if (opt[0]=='Q')
                    {
                            int now=0;
                            printf("%d
    ",t=find_sam(cc));
                            lastans^=t;
                    }else
                    {
                            int t=strlen(cc);
                            for (int i=0;i<t;i++)
                                    Add_sam(cc[i]);
                    }
            }
    }
  • 相关阅读:
    Android常见问题——找不到HttpClient和okHttp的包
    linux大文件的日志查询
    ubuntu ssh连不上
    linux查询核数
    ubuntu系统安装手动分区
    计算服务器带宽
    linux命令
    打包jar 运行
    打印pdf
    运行 jar 包
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4520777.html
Copyright © 2011-2022 走看看