码迷,mamicode.com
首页 > 其他好文 > 详细

2555: SubString 后缀自动机+LCT

时间:2015-05-21 22:29:29      阅读:257      评论:0      收藏:0      [点我收藏+]

标签:

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\n",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]=‘\0‘;
   }
   }*/
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\n",&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\n",opt,cc);
                int t;
                t=strlen(cc);
                Decode(cc,t,lastans);
                if (opt[0]==Q)
                {
                        int now=0;
                        printf("%d\n",t=find_sam(cc));
                        lastans^=t;
                }else
                {
                        int t=strlen(cc);
                        for (int i=0;i<t;i++)
                                Add_sam(cc[i]);
                }
        }
}

 

2555: SubString 后缀自动机+LCT

标签:

原文地址:http://www.cnblogs.com/mhy12345/p/4520777.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!