zoukankan      html  css  js  c++  java
  • [LOJ6198]谢特

    loj

    description

    给你一个字符串和一个数组(w_i),定义(mbox{LCP}(i,j))(i,j)两个后缀的最长公共前缀。求(max_{i,j}mbox{LCP}(i,j)+(w_i mbox{xor} w_j))
    (n le 10^5)

    sol

    首先,(mbox{LCP}(i,j))是后缀排序上的一段连续区间的(mbox{Height})最小值。
    那么我们可以枚举这个最小值出现的位置,那么跨越这个位置的所有点对的(mbox{LCP})就确定了。
    接下来我们只要考虑最大化(w_i mbox{xor} w_j)
    显然可以用可持久化(mbox{Tire})树实现,复杂度是查询次数( imes log n)的。

    算法流程大致是这样的:先找到(mbox{Height})最小的位置(p),计算所有跨越(p)的点对的答案。枚举分割点两侧(size)较小的一侧,在可持久化(mbox{Tire})树上查询它和另一侧异或的最大值。接着两侧被完全割裂开,可以分别递归下去处理。

    考虑这个东西的时间复杂度。可以发现这就是一个倒着做的启发式合并,所以复杂度就是(O(nlog^2n))
    当然也可以按(mbox{Height})从大到小启发式合并,复杂度是一样的。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi(){
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 1e5+5;
    struct node{int ch[2],sz;}tr[N*35];
    int n,t[N],x[N],y[N],SA[N],Rank[N],Height[N],st[19][N],lg[N],rt[N],tot,w[N],ans;
    char s[N];
    bool cmp(int i,int j,int k){
    	return y[i]==y[j]&&y[i+k]==y[j+k];
    }
    void getSA(){
    	int m=30;
    	for (int i=1;i<=n;++i) ++t[x[i]=s[i]-'a'+1];
    	for (int i=1;i<=m;++i) t[i]+=t[i-1];
    	for (int i=n;i;--i) SA[t[x[i]]--]=i;
    	for (int k=1;k<=n;k<<=1){
    		int p=0;
    		for (int i=0;i<=m;++i) y[i]=0;
    		for (int i=n-k+1;i<=n;++i) y[++p]=i;
    		for (int i=1;i<=n;++i) if (SA[i]>k) y[++p]=SA[i]-k;
    		for (int i=0;i<=m;++i) t[i]=0;
    		for (int i=1;i<=n;++i) ++t[x[y[i]]];
    		for (int i=1;i<=m;++i) t[i]+=t[i-1];
    		for (int i=n;i;--i) SA[t[x[y[i]]]--]=y[i];
    		swap(x,y);x[SA[1]]=p=1;
    		for (int i=2;i<=n;++i) x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
    		if (p>=n) break;m=p;
    	}
    	for (int i=1;i<=n;++i) Rank[SA[i]]=i;
    	for (int i=1,j=0;i<=n;++i){
    		if (j) --j;
    		while (s[i+j]==s[SA[Rank[i]-1]+j]) ++j;
    		Height[Rank[i]]=j;st[0][i]=i;
    	}
    	for (int i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
    	for (int j=1;j<=lg[n];++j)
    		for (int i=1;i+(1<<j)-1<=n;++i)
    			if (Height[st[j-1][i]]<Height[st[j-1][i+(1<<j-1)]])
    				st[j][i]=st[j-1][i];
    			else st[j][i]=st[j-1][i+(1<<j-1)];
    }
    int cal(int l,int r){
    	int k=lg[r-l+1];
    	if (Height[st[k][l]]<Height[st[k][r-(1<<k)+1]]) return st[k][l];
    	return st[k][r-(1<<k)+1];
    }
    void modify(int &x,int p,int dep){
    	tr[++tot]=tr[x];++tr[x=tot].sz;
    	if (!~dep) return;
    	modify(tr[x].ch[(p>>dep)&1],p,dep-1);
    }
    int query(int x,int y,int p,int dep){
    	if (!~dep) return 0;
    	int c=(p>>dep)&1;c^=1;
    	if (tr[tr[x].ch[c]].sz-tr[tr[y].ch[c]].sz) return query(tr[x].ch[c],tr[y].ch[c],p,dep-1)|(1<<dep);
    	c^=1;return query(tr[x].ch[c],tr[y].ch[c],p,dep-1);
    }
    void solve(int l,int r){
    	if (l==r) return;int mid=cal(l+1,r)-1;
    	if (mid-l+1<=r-mid){
    		for (int i=l;i<=mid;++i)
    			ans=max(ans,Height[mid+1]+query(rt[r],rt[mid],w[SA[i]],18));
    	}else{
    		for (int i=mid+1;i<=r;++i)
    			ans=max(ans,Height[mid+1]+query(rt[mid],rt[l-1],w[SA[i]],18));
    	}
    	solve(l,mid);solve(mid+1,r);
    }
    int main(){
    	n=gi();scanf("%s",s+1);getSA();
    	for (int i=1;i<=n;++i) w[i]=gi();
    	for (int i=1;i<=n;++i) modify(rt[i]=rt[i-1],w[SA[i]],18);
    	solve(1,n);printf("%d
    ",ans);return 0;
    }
    
  • 相关阅读:
    微信小程序HTTPS
    微信商城-1简介
    va_list
    Event log c++ sample.
    EVENT LOGGING
    Analyze Program Runtime Stack
    unknow table alarmtemp error when drop database (mysql)
    This application has request the Runtime to terminate it in an unusual way.
    How to check if Visual Studio 2005 SP1 is installed
    SetUnhandledExceptionFilter
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9385717.html
Copyright © 2011-2022 走看看