【LOJ6198】谢特(后缀自动机)(01Trie)(dsu on tree)

传送门


题解:

写完去看了一下正解,是后缀数组上按照height从大到小对01Trie启发式合并。

然而建出后缀树直接把01Trie拿来dsu on tree岂不妙哉?

没什么好说的,挺普通的一道题。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	inline int get_s(char *s){
		int len=0;char c;
		while(isspace(c=gc()));
		while(s[len++]=c,!isspace(c=gc())&&c!=EOF);
		s[len]='\0';return len;
	}
	
	template<typename T>
	inline T get(){
		char c;
		while(!isdigit(c=gc()));T num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int getint(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int N=1e5+5;

int n;
char s[N];
int w[N];
int ans;

namespace Trie{
	cs int N=::N*20,B=17;
	int son[N][2],tot;
	
	inline void clear(){
		while(tot){
			son[tot][0]=son[tot][1]=0;
			--tot;
		}
		son[0][0]=son[0][1]=0;
	}
	
	inline void ins(int val){
		int cur=0;
		for(int re i=B-1;~i;--i){
			bool f=val&(1<<i);
			if(!son[cur][f])son[cur][f]=++tot;
			cur=son[cur][f];
		}
	}
	
	inline int query(int val){
		if(!tot)return -1e9;
		int cur=0,res=0;
		for(int re i=B-1;~i;--i){
			bool f=val&(1<<i);
			if(son[cur][!f])res|=1<<i,cur=son[cur][!f];
			else cur=son[cur][f];
		}
		return res;
	}
}

namespace SAM{
	static cs int N=::N<<1;
	int son[N][26],len[N],fa[N],last=1,now=1;
	int val[N];
	
	inline void push_back(char c,int w){
		c-='a';
		int p=last,cur=last=++now;
		len[cur]=len[p]+1;val[cur]=w;
		for(;p&&!son[p][c];p=fa[p])son[p][c]=cur;
		if(!p)fa[cur]=1;
		else if(len[son[p][c]]==len[p]+1)fa[cur]=son[p][c];
		else {
			int nq=++now,q=son[p][c];
			val[nq]=-1;
			memcpy(son[nq],son[q],sizeof son[q]);
			len[nq]=len[p]+1;fa[nq]=fa[q];
			fa[q]=fa[cur]=nq;
			for(;p&&son[p][c]==q;p=fa[p])son[p][c]=nq;
		}
	}
	
	std::vector<int> E[N];
	int in[N],out[N],p[N],clk;
	int siz[N],ch[N];
	
	inline void build(){
		for(int re i=n;i;--i)push_back(s[i],w[i]);
		for(int re i=2;i<=now;++i)E[fa[i]].push_back(i);
	}
	
	void dfs(int u){
		siz[u]=val[u]!=-1;
		p[in[u]=++clk]=u;
		for(int re v:E[u]){
			dfs(v);
			siz[u]+=siz[v];
			if(siz[v]>siz[ch[u]])ch[u]=v;
		}
		out[u]=clk;
	}
	
	void dsu(int u){
		for(int re v:E[u])if(v!=ch[u])dsu(v),Trie::clear();
		if(ch[u])dsu(ch[u]);
		for(int re v:E[u])if(v!=ch[u]){
			for(int re i=in[v];i<=out[v];++i)if(~val[p[i]])
			ans=std::max(ans,len[u]+Trie::query(val[p[i]]));
			for(int re i=in[v];i<=out[v];++i)if(~val[p[i]])
			Trie::ins(val[p[i]]);
		}
		if(~val[u]){
			ans=std::max(ans,len[u]+Trie::query(val[u]));
			Trie::ins(val[u]);
		}
	}
}

signed main(){
//	freopen("shit.in","r",stdin);
	n=getint();
	get_s(s+1);
	for(int re i=1;i<=n;++i)w[i]=getint();
	SAM::build();
	SAM::dfs(1);
	SAM::dsu(1);
	cout<<ans<<"\n";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值