• BZOJ 2555 SubString


    题解:用LCT维护parent树的Right集合大小

    为什么我的代码这么慢???

    问题:对SAM理解的还不够深

    吐槽:神加密

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int maxn=1200009;
    
    int T;
    
    int fa[maxn],ch[maxn][2],tag[maxn],v[maxn],rev[maxn];
    inline int son(int x){
    	if(ch[fa[x]][1]==x)return 1;
    	else return 0;
    }
    inline bool isroot(int x){
    	return (ch[fa[x]][0]!=x)&&(ch[fa[x]][1]!=x);
    }
    inline void pushup(int x){
    }
    inline void pushdown(int x){
    	if(tag[x]){
    		tag[ch[x][0]]+=tag[x];
    		tag[ch[x][1]]+=tag[x];
    		v[ch[x][0]]+=tag[x];
    		v[ch[x][1]]+=tag[x];
    		tag[x]=0;
    	}
    	if(rev[x]){
    		rev[ch[x][0]]^=1;
    		rev[ch[x][1]]^=1;
    		rev[x]^=1;
    		swap(ch[x][0],ch[x][1]);
    	}
    }
    void Downfa(int x){
    	if(!isroot(x))Downfa(fa[x]);
    	pushdown(x);
    }
    
    inline void Rotate(int x){
    	int y=fa[x];
    	int z=fa[y];
    	int b=son(x),c=son(y);
    	int a=ch[x][b^1];
    	if(!isroot(y))ch[z][c]=x;
    	fa[x]=z;
    	if(a)fa[a]=y;
    	ch[y][b]=a;
    	fa[y]=x;ch[x][b^1]=y;
    	pushup(y);pushup(x);
    }
    void Splay(int x){
    	Downfa(x);
    	while(!isroot(x)){
    		int y=fa[x];
    		if(isroot(y)){
    			Rotate(x);
    		}else{
    			if(son(x)==son(y)){
    				Rotate(y);Rotate(x);
    			}else{
    				Rotate(x);Rotate(x);
    			}
    		}
    	}
    }
    
    void Access(int x){
    	for(int t=0;x;t=x,x=fa[x]){
    		Splay(x);ch[x][1]=t;pushup(x);
    	}
    }
    void Makeroot(int x){
    	Access(x);Splay(x);rev[x]^=1;
    }
    void Linkp(int x,int y){
    	Makeroot(x);fa[x]=y;
    }
    void Cutp(int x,int y){
    	Makeroot(x);Access(y);Splay(y);
    	fa[ch[y][0]]=0;ch[y][0]=0;pushup(y);
    }
    void Addpath(int x,int y){
    	Makeroot(x);Access(y);Splay(y);
    	tag[y]+=1;v[y]+=1;
    }
    
    int SAMsiz,last,cur;
    int ch2[maxn][27];
    int dis[maxn];
    int par[maxn];
    void BuildSAM(int c,int idp){
    	cur=++SAMsiz;
    	dis[cur]=idp;
    	int p=last;last=cur;
    	for(;p&&!ch2[p][c];p=par[p])ch2[p][c]=cur;
    	if(!p){
    		par[cur]=1;
    		Linkp(cur,1);
    		Addpath(1,cur);
    	}else{
    		int q=ch2[p][c];
    		if(dis[q]==dis[p]+1){
    			par[cur]=q;
    			Linkp(cur,q);
    			Addpath(1,cur);
    		}else{
    			int nt=++SAMsiz;
    			memcpy(ch2[nt],ch2[q],sizeof(ch2[nt]));
    			dis[nt]=dis[p]+1;
    			Cutp(q,par[q]);
    			Linkp(q,nt);
    			Linkp(nt,par[q]);
    			Linkp(cur,nt);
    			Splay(q);Splay(nt);
    			v[nt]=v[q];
    			Addpath(1,cur);
    			par[nt]=par[q];
    			par[q]=par[cur]=nt;
    			for(;ch2[p][c]==q;p=par[p])ch2[p][c]=nt;
    		}
    	}
    }
    
    int mask,m,nowlen;
    char opty[maxn];
    char opts[maxn];
    void Decode(){
    //	return;
    	int t=mask;
    	for(int i=0;i<m;++i){
    		t=(t*131+i)%m;
    		swap(opts[i],opts[t]);
    	}
    }
    void Addstring(){
    	for(int i=0;i<m;++i)BuildSAM(opts[i]-'A',nowlen+i+1);
    	nowlen+=m;
    }
    int Getans(){
    	int x=1;
    	for(int i=0;i<m;++i){
    		int c=opts[i]-'A';
    		x=ch2[x][c];
    	}
    	if(!x)return 0;
    	Splay(x);
    	return v[x];
    }
    
    int main(){
    	scanf("%d",&T);
    	
    	SAMsiz=last=1;
    	scanf("%s",opts);
    	nowlen=m=strlen(opts);
    	for(int i=0;i<m;++i)BuildSAM(opts[i]-'A',i+1);
    	
    	while(T--){
    		scanf("%s%s",opty,opts);
    		m=strlen(opts);
    		Decode();
    		if(opty[0]=='A'){
    			Addstring();
    		}else{
    			int ans=Getans();
    			printf("%d
    ",ans);
    			mask^=ans;
    		}
    	}
    	return 0;
    }
    

      

    自己还是太辣鸡了
  • 相关阅读:
    DataGridView 设置行不可见时,与货币管理器的位置关联的行不能设置为不可见
    DataGridView 冻结列后出现 无法添加该列,原因是它被冻结并被置于未冻结的列之后
    sql 2000 查询中增加序号列,自动增加列
    SQL 语法大全
    清除vs2003vs2008起始页最近打开项目
    ALTER TABLE 修改表时 因为有一个或多个对象访问此列
    UNIX上C++程序设计守则(信号和线程)(上)
    Thread Cancel 指南
    [C++再学习系列] 深入new/delete:New的3种形态
    设计模式学习(六):重构与模式,推荐书籍(完)
  • 原文地址:https://www.cnblogs.com/zzyer/p/8454318.html
Copyright © 2020-2023  润新知