• BZOJ2555: SubString


    题面:https://www.lydsy.com/JudgeOnline/problem.php?id=2555
    题解:
    如果没有修改操作,这就是一道SAM模板题。
    有了修改操作后,发现fail树可能会有断边的过程,
    不难想到使用LCT维护fail树。
    每次加边时,需要将贡献也一并加入LCT的节点中,
    查询时,找到对应节点,将其splay到根,此时的val就是答案。
    注意:
    1.splay时记得要pushdown;
    2.是大写字母;
    3.数组要开到(1.2e6)
    时间复杂度:(O(n+Qlogn))
    代码:

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    using namespace std;
    #define re register int
    #define F(x,y,z) for(re x=y;x<=z;x++)
    #define FOR(x,y,z) for(re x=y;x>=z;x--)
    typedef long long ll;
    #define I inline void
    #define IN inline int
    #define C(x,y) memset(x,y,sizeof(x))
    #define STS system("pause")
    template<class D>I read(D &res){
    	res=0;register D g=1;register char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')g=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)){
    		res=(res<<3)+(res<<1)+(ch^48);
    		ch=getchar();
    	}
    	res*=g;
    }
    char c[3030000];
    int n,m,Q;
    namespace LCT{
    	int fa[1202000],ch[1202000][2],laz[1202000],w[1202000];
    	int st[1202000];
    	IN nroot(int x){
    		return (ch[fa[x]][0]==x)||(ch[fa[x]][1]==x);
    	}
    	IN get(int x){
    		return ch[fa[x]][1]==x;
    	}
    	I add(int x,int val){
    		if(!x)return;laz[x]+=val;w[x]+=val;
    	}
    	I push_down(int x){
    		add(ch[x][0],laz[x]);add(ch[x][1],laz[x]);
    		laz[x]=0;
    	}
    	I rotate(int x){
    		re y=fa[x],z=fa[y],dir=get(x);
    		if(nroot(y))ch[z][get(y)]=x;fa[x]=z;
    		ch[y][dir]=ch[x][dir^1];fa[ch[x][dir^1]]=y;
    		ch[x][dir^1]=y;fa[y]=x;
    	}
    	I splay(int x){
    		re y=x,z=0;st[++z]=y;
    		while(y)st[++z]=y=fa[y];
    		while(z)push_down(st[z--]);
    		while(nroot(x)){
    			y=fa[x],z=fa[y];
    			if(nroot(y))rotate((get(x)^get(y))?x:y);
    			rotate(x);
    		}
    	}
    	I access(int x){
    		for(re y=0;x;x=fa[y=x])splay(x),ch[x][1]=y;
    	}
    	I link(int x,int y){
    		fa[x]=y;access(y);splay(y);add(y,w[x]);
    	}
    	I cut(int x,int y){
    		access(x);splay(x);add(ch[x][0],-w[x]);
    		fa[ch[x][0]]=0;ch[x][0]=0;
    	}
    };
    namespace SAM{
    	int len[1202000],ch[1202000][27],link[1202000],tot,las,p,q,cle,cur;
    	I init(){tot=las=1;}
    	I add(int x){
    		cur=++tot;len[cur]=len[las]+1;p=las;las=cur;LCT::w[cur]=1;
    		while(p&&!ch[p][x])ch[p][x]=cur,p=link[p];
    		if(!p){link[cur]=1;LCT::link(cur,1);return;}
    		q=ch[p][x];
    		if(len[p]+1==len[q]){link[cur]=q;LCT::link(cur,q);return;}
    		cle=++tot;len[cle]=len[p]+1,link[cle]=link[q];LCT::link(cle,link[cle]);
    		memcpy(ch[cle],ch[q],sizeof(ch[q]));
    		LCT::cut(q,link[q]);link[q]=cle;LCT::link(q,link[q]);link[cur]=cle;LCT::link(cur,cle);
    		while(p&&ch[p][x]==q)ch[p][x]=cle,p=link[p];
    	}
    	I insert(){F(i,0,n-1)add(c[i]-'A'+1);}
    	I ques(){
    		p=1;
    		F(i,0,n-1){
    			if(!ch[p][c[i]-'A'+1]){
    				printf("0
    ");return;
    			}
    			p=ch[p][c[i]-'A'+1];
    		}
    		LCT::splay(p);
    		printf("%d
    ",LCT::w[p]);m^=LCT::w[p];
    	} 
    };
    I getit(int x){
    	scanf("%s",c);n=strlen(c);
    	F(i,0,n-1){
    		x=(x*131+i)%n;
    		swap(c[i],c[x]);
    	}
    }
    int main(){
    	read(Q);m=0;
    	scanf("%s",c);
    	n=strlen(c);
    	SAM::init();
    	SAM::insert();
    	while(Q--){
    		scanf("%s",c+1);
    		if(c[1]=='A'){
    			getit(m);SAM::insert();
    		}
    		else{
    			getit(m);SAM::ques();
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Android学习之DatePicker和TimePicker
    Android学习之Spinner
    Android学习之Handler消息
    Android学习之Dialog
    Android学习之SeekBar(控制wav音频的声音)
    Android学习之Gallery
    android R文件不能识别?
    Android学习之RadioGroup和RadioButton
    Android中实现定时器的3中方法
    activity的启动模式有哪些?
  • 原文地址:https://www.cnblogs.com/Purple-wzy/p/12169531.html
Copyright © 2020-2023  润新知