• 【LOJ#6198】—谢特(后缀数组+01Trie)


    传送门

    建出后缀数组按照heightheight合并连通块
    维护01Trie01Trie合并,启发式询问即可

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=(1<<20)|5;
    inline char gc(){
    	static char ibuf[RLEN],*ib,*ob;
    	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    	return (ib==ob)?EOF:*ib++;
    }
    #define gc getchar
    inline int read(){
    	char ch=gc();
    	int res=0,f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    	return f?res:-res;
    }
    #define pb push_back
    #define re register
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define cs const
    #define bg begin
    #define ll long long
    
    template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
    template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
    cs int N=100005;
    char xxx;
    namespace Trie{
    	cs int M=N*30;
    	int tot,son[M][2],siz[M];
    	void insert(int &u,int k,int dep){
    		if(!u)u=++tot;siz[u]++;
    		if(dep<0)return;
    		insert(son[u][(k>>dep)&1],k,dep-1);
    	}
    	int query(int &u,int k,int dep){
    		if(dep<0)return 0;
    		int t=(k>>dep)&1;
    		if(siz[son[u][t^1]])return (1<<dep)+query(son[u][t^1],k,dep-1);
    		else return query(son[u][t],k,dep-1);
    	}
    	void merge(int &u,int r1,int r2){
    		if(!r1||!r2){u=r1+r2;return;}
    		u=r1,siz[u]=siz[r1]+siz[r2];
    		merge(son[u][0],son[r1][0],son[r2][0]);
    		merge(son[u][1],son[r1][1],son[r2][1]);
    	}
    }
    int ans;
    namespace Sa{
    	int sa[N],sa2[N],s[N],rk[N],buc[N],ht[N];
    	int n,m;
    	inline void buc_sort(){
    		for(int i=1;i<=m;i++)buc[i]=0;
    		for(int i=1;i<=n;i++)buc[rk[sa2[i]]]++;
    		for(int i=1;i<=m;i++)buc[i]+=buc[i-1];
    		for(int i=n;i>=1;i--)sa[buc[rk[sa2[i]]]--]=sa2[i];
    	}
    	inline void build(char *ss,int _n){
    		n=_n;m=27;
    		for(int i=1;i<=n;i++)s[i]=ss[i]-'a'+1,rk[i]=s[i],sa2[i]=i;
    		buc_sort();
    		for(int pos=0,i=1;i<=n&&pos<n;i<<=1){
    			pos=0;
    			for(int j=n-i+1;j<=n;j++)sa2[++pos]=j;
    			for(int j=1;j<=n;j++)if(sa[j]>i)sa2[++pos]=sa[j]-i;
    			buc_sort();
    			swap(rk,sa2);
    			pos=1,rk[sa[1]]=1;
    			for(int j=2;j<=n;j++)
    			rk[sa[j]]=(sa2[sa[j]]==sa2[sa[j-1]]&&sa2[sa[j]+i]==sa2[sa[j-1]+i])?pos:++pos;
    			m=pos;
    		}
    		for(int i=1,j,k=0;i<=n;ht[rk[i++]]=k)
    		for(k?k--:0,j=sa[rk[i]-1];s[j+k]==s[i+k];k++);
    	}
    	int fa[N],rt[N],w[N];
    	int p[N];
    	vector<int> st[N];
    	inline bool comp(int a,int b){
    		return ht[a]>ht[b];
    	}
    	inline int find(int x){
    		return fa[x]==x?x:fa[x]=find(fa[x]);
    	}
    	inline void merge(int x,int y,int k){
    		int f1=find(x),f2=find(y);
    		if(st[f1].size()>st[f2].size())swap(f1,f2);
    		fa[f1]=f2;int res=0;
    		for(int &x:st[f1]){
    			chemx(res,Trie::query(rt[f2],w[x],18));
    			st[f2].pb(x);
    		}
    		Trie::merge(rt[f2],rt[f1],rt[f2]);
    		chemx(ans,res+k);
    	}
    	inline void solve(){
    		for(int i=1;i<=n;i++)fa[i]=i,st[i].pb(i),Trie::insert(rt[i],w[i],18);
    		for(int i=2;i<=n;i++)p[i-1]=i;
    		sort(p+1,p+n,comp);
    		for(int i=1;i<n;i++){
    			int pos=p[i];
    			merge(pos,pos-1,ht[pos]);
    		}
    		cout<<ans;
    	}
    }
    int n;
    char s[N];
    char yyy;
    int main(){
    	n=read();
    	scanf("%s",s+1);
    	Sa::build(s,n);
    	for(int i=1;i<=n;i++)Sa::w[Sa::rk[i]]=read();
    	Sa::solve();
    }
    
  • 相关阅读:
    Linux 下IOport编程訪问
    Xcode下执行HelloWorld
    PHP/HTML混写的四种方式总结
    php取两位小数的几种方法
    使用原生JS+CSS或HTML5实现简单的进度条和滑动条效果(精问)
    js进阶 9-7 自动计算商品价值
    html5--1.12表格详解
    html5常用标签table表格布局
    html常用属性border-radius、linear-gradient怎么使用
    类选择器选择非唯一属性无法精确取值的问题
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328392.html
Copyright © 2020-2023  润新知