• 洛谷 P5212 SubString【SAM+LCT】


    传送门
    如果这题可以离线的话当然就SAM+线段树合并了,但是它居然来了个强制在线,给了个神奇的解码函数,我没有注意mask是传的参数,交上去直接WA,怀疑人生。
    当然这题要强制在线的话就用LCT来维护parent树,维护子树和就行了,LCT的link和cut与sam里fa指针的动作保持一致就很好维护了。
    当然询问的时候可以先断开p与fa[p]的链接,然后将p设为根,查p的子树和就ok,然后再连接p和fa[p]。
    不知道为什么不开O2直接超时,开了O2速度能跑进第一页……可能是因为makeroot操作有点多余吧,我看题解有说没有必要makeroot的,但是我有点没想明白为什么,而且我不makeroot还会错。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=4e6+10;
    
    struct LCT{
    	int fa[N*2],ch[N*2][2],f[N*2],f2[N*2],rev[N*2],val[N*2];
    	#define ls(x) (ch[x][0])
    	#define rs(x) (ch[x][1])
    	#define ident(p,f) (ch[f][1]==p)
    	#define connect(p,f,k) (ch[fa[p]=f][k]=p)
    	#define ntroot(p) (ls(fa[p])==p||rs(fa[p])==p)
    	inline void pushup(int p) {f[p]=f[rs(p)]+f[ls(p)]+val[p]+f2[p];}
    	inline void Rev(int p){swap(ls(p),rs(p));rev[p]^=1;}
    	inline void pushdw(int p){if(rev[p]) Rev(ls(p)),Rev(rs(p));rev[p]=0;}
    	inline void rotate(int p){
    		int f=fa[p],ff=fa[f],k=ident(p,f);
    		connect(ch[p][k^1],f,k);
    		fa[p]=ff;
    		if(ntroot(f)) ch[ff][ident(f,ff)]=p;
    		connect(f,p,k^1);
    		pushup(f),pushup(p);
    	}
    	inline void pushall(int p){if(ntroot(p)) pushall(fa[p]);pushdw(p);}
    	inline void splay(int p){
    		pushall(p);
    		while(ntroot(p)){
    			int f=fa[p],ff=fa[f];
    			if(ntroot(f)) ident(p,f)^ident(f,ff)?rotate(p):rotate(f);
    			rotate(p);
    		}
    	}
    	void access(int p){
    		for(int t=0;p;p=fa[t=p])
    			splay(p),f2[p]+=f[rs(p)]-f[t],
    			rs(p)=t,pushup(p);
    	}
    	void makert(int p){
    		access(p);splay(p);Rev(p);
    	}
    	int findrt(int p){
    		access(p);splay(p);
    		while(ls(p)) p=ls(p),pushdw(p);
    		splay(p);return p;
    	}
    	void split(int p,int q){
    		makert(p);access(q);splay(q);
    	}
    	void link(int p,int q){
    		makert(p);makert(q);fa[p]=q;
    		f2[q]+=f[p];pushup(q);
    	}
    	void cut(int p,int q){
    		split(p,q);fa[p]=ls(q)=0;pushup(q);
    	}
    }lct;
    
    int n,m,mask;
    char s[N];
    
    struct SuffixAutomaton{
    	int last=1,tot=1,fa[N*2],len[N*2],ch[N*2][2];
    	int newnode(int x){fa[++tot]=fa[x];len[tot]=len[x];memcpy(ch[tot],ch[x],sizeof(ch[tot]));return tot;}
    	void append(int c){
    		int p=last,np=last=newnode(0);
    		len[np]=len[p]+1; lct.val[np]=1;
    		for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
    		if(!p) fa[np]=1;
    		else if(len[ch[p][c]]==len[p]+1) fa[np]=ch[p][c];
    		else{
    			int q=ch[p][c],nq=newnode(q);len[nq]=len[p]+1;
    			lct.cut(q,fa[q]);
    			lct.link(nq,fa[q]);
    			fa[q]=fa[np]=nq;
    			lct.link(q,nq);
    			for(;p&&ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
    		}
    		lct.link(np,fa[np]);
    	}
    	int ask(){
    		int p=1,flag=1;
    		for(int i=0;i<n;i++)
    			if(ch[p][s[i]-'A']) p=ch[p][s[i]-'A'];
    			else {flag=0;break;}
    		if(!flag) return 0;
    		lct.cut(p,fa[p]);
    		lct.splay(p);
    		int res=lct.f[p];
    		lct.link(p,fa[p]);
    		return res;
    	}
    }sam;
    
    void decode(int mask){
    	for(int i=0;i<n;i++){
    		mask=(mask*131+i)%n;
    		swap(s[i],s[mask]);
    	}
    }
    
    int main(){
    	scanf("%d",&m);
    	scanf("%s",s);
    	n=strlen(s);
    	for(int i=0;i<n;i++) sam.append(s[i]-'A');
    	while(m--){
    		char opt[10];
    		scanf("%s%s",opt,s);
    		n=strlen(s);decode(mask);
    		if(opt[0]=='A'){
    			for(int i=0;i<n;i++) sam.append(s[i]-'A');
    		}
    		else{
    			int res=sam.ask();
    			printf("%d
    ",res);
    			mask^=res;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    左旋转字符串
    swoole(8)http服务
    整数反转
    两数之和
    广度优先搜索
    快速排序
    JavaScript当中的eval函数
    JavaScript中的作用域链原理
    git push和git pull
    cherry-pick,revert和rebase使用的3-way合并策略
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/12718446.html
Copyright © 2020-2023  润新知