zoukankan      html  css  js  c++  java
  • BZOJ 2555: SubString

    BZOJ 2555: SubString

    标签(空格分隔): OI-BZOJ OI-后缀自动机 OI-LCT


    Time Limit: 30 Sec
    Memory Limit: 512 MB


    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


    Solution####

    给一组自己玩的数据:
    10
    A
    QUERY B
    ADD BBABBBBAAB
    QUERY AB
    ADD BBABBBBAAB
    QUERY ABB
    ADD BBABBBBAAB
    QUERY ABB
    ADD BBABBBBAAB
    QUERY ABB
    ADD BBABBBBAAB

    输出
    0
    3
    4
    3
    6

    构造后缀自动机,每个状态的right集合大小即为当前串的出现次数。
    用LCT维护自动机的fail树在线得到每个点的right集合大小


    Code####

    #include<iostream>
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<bitset>
    #include<vector>
    using namespace std;
    #define PA pair<int,int>
    int read()
    {
     	int s=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+ch-'0';ch=getchar();}
    	return s*f;
    }
    //smile please
    const int N=600005;
    struct tree;
    extern tree t[N*2];
    struct tree
    {
    	int w[2],f,s,r,la;
    	void down()
     	   {
    		if(r)swap(w[0],w[1]);
    	    if(w[0])t[w[0]].r^=r;
    		if(w[1])t[w[1]].r^=r;r=0;
    	    s+=la;
    	    if(w[0])t[w[0]].la+=la;
    	    if(w[1])t[w[1]].la+=la;
    		la=0;
    	   }
    	void updata()
    	   {
    	   }
    }t[N*2];
    bool notroot(int x)
    {
    	return t[t[x].f].w[0]==x||t[t[x].f].w[1]==x;
    }
    void rotate(int x)
    {
    	int f=t[x].f,r=(t[f].w[1]==x);
    	t[x].f=t[f].f;
    	if(notroot(f))
    	  t[t[f].f].w[t[t[f].f].w[1]==f]=x;
    	t[f].w[r]=t[x].w[!r];
    	if(t[x].w[!r])
    	  t[t[x].w[!r]].f=f;
    	t[f].f=x;
    	t[x].w[!r]=f;
    	t[f].updata();
    }
    int sta[N*2];
    void splay(int x)
    {
    	if(x==0)return;
    	for(sta[++sta[0]]=x;notroot(sta[sta[0]]);)
    	    sta[++sta[0]]=t[sta[sta[0]-1]].f;
     	while(sta[0])t[sta[sta[0]--]].down();
    	for(int f;notroot(x);rotate(x))
    	    if(notroot(f=t[x].f))
    	      rotate(t[t[f].f].w[1]==f^t[f].w[1]==x?x:f);
    	t[x].updata();
    }
    void access(int x){int xx=x;for(int las=0;x;splay(x),t[x].w[1]=las,las=x,x=t[x].f);splay(xx);}
    struct samm
    {
    	int last,total;
    	int L[N*2],ch[N*2][26],fa[N*2];//,val[N*2];
    	samm(){total=1,last=1;}
    	void plu(int x,int s)
    	   {//for(;x;x=fa[x])
    	    //    val[x]+=s;
    	    access(x);t[x].la+=s;
    	   }
    	void fu(int x,int y)
    	   {
    	    splay(x),splay(y);
    		if(fa[x])
    		   {if(t[x].s)plu(fa[x],-t[x].s);
    		    access(fa[x]);splay(x);t[x].f=0;
    		   }
    		t[x].f=y;
    		access(x);
    		if(t[x].s)
    		  plu(y,t[x].s);
    		fa[x]=y;
    	   }
    	void insert(int C)
    	   {int p=last,now=last=++total;
    	    L[now]=L[p]+1;t[now].s=1;
    		for(;p&&!ch[p][C];p=fa[p])
    	        ch[p][C]=now;
    	    if(!p){fu(now,1);return;}
    	    
    		if(L[ch[p][C]]==L[p]+1){fu(now,ch[p][C]);return;}
    	    
    		int ne=++total,Q=ch[p][C];
    	    memcpy(ch[ne],ch[Q],sizeof(ch[Q]));
    	    fu(ne,fa[Q]);
    	    fu(Q,ne);fu(now,ne);
    	    L[ne]=L[p]+1;
    	    for(;p&&ch[p][C]==Q;p=fa[p])
    	        ch[p][C]=ne;
    	   }
    	int ST(char z[],int len)
    	   {int now=1;
    	    for(int i=0;i<len;i++)
    	        now=ch[now][z[i]-'A'];
    	    return now;
    	   }
    	void print()
    	   {
    		for(int i=1;i<=total;i++)
    	    	printf("%d: f_%d l_%d a_%d b_%d c_%d
    ",i,fa[i],L[i],ch[i][0],ch[i][1],ch[i][2]);
    	   }
    }a;
    int len;
    char z[3000005];
    int Q,mask;
    void readstr()
    {
    	len=0;z[0]=getchar();
    	while(z[0]<'A'||z[len]>'Z')z[0]=getchar();
    	while(z[len]>='A'&&z[len]<='Z')z[++len]=getchar();
    	z[len]=0;
    }
    void decode(int mask)
    {
    	for(int i=0;i<len;i++)
    	   {mask=(mask*131+i)%len;
    	    swap(z[i],z[mask]);
    	   }
    }
    int solve()
    {
    	int x=a.ST(z,len);
    	splay(x);
    	return t[x].s;
    }
    int main()
    {
     	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
    	Q=read();
    	readstr();
    	for(int i=0;i<len;i++)
    	    a.insert(z[i]-'A');
    	while(Q--)
    	   {readstr();
    	    if(z[0]=='A')
    	       {readstr();decode(mask);
    	   	    for(int i=0;i<len;i++)
    	   	        a.insert(z[i]-'A');
    		   }
    		else
    		   {readstr();decode(mask);
    	   		int ans=solve();
    	   		mask^=ans;
    	   		printf("%d
    ",ans);
    		   }
    	   }
    	//fclose(stdin);
    	//fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    信用卡知识:自动扣款日不等于最后还款日_刷卡技巧_财经_腾讯网
    北京,大兴,采育,京福路边上。嘿嘿,交通还是很便利的。
    想知道:北京市 亦庄交通队在哪?
    bda_百度百科
    聚合服务资费标准
    公租自行车-北京经济技术开发区
    北京公共自行车-北京市交通委员会运输管理局
    北京公共自行车租赁方法_百度知道
    NEXT | 不错过任何一个新产品
    吸血鬼日记 第五季 16 | 美剧单词
  • 原文地址:https://www.cnblogs.com/wuyuhan/p/5293927.html
Copyright © 2011-2022 走看看