• ●BZOJ 4556 [Tjoi2016&Heoi2016]字符串


    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=4556

    题解:

    巨恶心。。。但是题很好呀,可以练习好几个比较麻烦的算法~

    1).预处理
    首先用倍增算法求出 sa[],以及rank[],height[]。
    并且对 height[]数组建立ST表。
    按顺序对rank[]建立主席树。
    (第i颗树的节点 u[l,r]保存了在 rank[1]~rank[i]这个前缀内,出现了多少个权值在 l~r内的rank值(num))

    2).在线查询
    对于一组询问(a,b,c,d),先二分答案 X,下面即是判定:
    用rank[]数组得到后缀 c在后缀数组中的位置 P。
    然后再求出在后缀数组中从p向上延伸到的最远位置 L,使得 LCP(L,P)>=X。
    同理,向下延伸到最远位置 R,使得 LCP(P,R)>=X。
    (求法呢,可以用二分,也可以用倍增求,类似倍增法求LCA,在求得时候需要用到 RMQ)
    接下来,就要用到主席树了。
    既然求出了与后缀c的LCP>=X的后缀在后缀数组中的排名范围[L,R]
    那么就查询主席树 rt[a-1]~rt[b-X+1]中的权值区间 [L,R]的值num是否大于 0即可。
    (如果 num>0,即表明在 S[a~b]内存在一个子串与后缀 c的LCP至少为 X)

    复杂度:O(n*log2N*log2N),有点卡时间,BZOJ上花了 14S.

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 100005
    #define rint register int
    #define filein(x) freopen(#x".in","r",stdin);
    #define fileout(x) freopen(#x".out","w",stdout);
    using namespace std;
    char S[MAXN];
    int sa[MAXN],rak[MAXN],hei[MAXN],stm[MAXN][20],log2[MAXN];
    struct CMT{//Chairman Tree (QAQ)
    	int	rt[MAXN],ls[MAXN*20],rs[MAXN*20],num[MAXN*20],siz;
    	void pushup(int u){
    		num[u]=num[ls[u]]+num[rs[u]];
    	}
    	void reset(int &u,int l,int r){
    		u=++siz; num[u]=0;
    		if(l==r) return;
    		int mid=(l+r)>>1;
    		reset(ls[u],l,mid);
    		reset(rs[u],mid+1,r);
    	}
    	void build(int &u,int l,int r,int p,int v){
    		u=++siz;
    		if(l==r){num[u]=1; return;}
    		ls[u]=ls[v]; rs[u]=rs[v];
    		int mid=(l+r)>>1;
    		if(p<=mid) build(ls[u],l,mid,p,ls[v]);
    		else build(rs[u],mid+1,r,p,rs[v]);
    		pushup(u);
    	}
    	int query(int lu,int ru,int l,int r,int al,int ar){//左开右闭
    		if(al<=l&&r<=ar) return num[ru]-num[lu];
    		int mid=(l+r)>>1,now=0;
    		if(al<=mid) 
    			now+=query(ls[lu],ls[ru],l,mid,al,ar);
    		if(mid<ar)
    			now+=query(rs[lu],rs[ru],mid+1,r,al,ar);
    		return now;
    	}
    }T;
    void build(int N,int M){
    	static int ta[MAXN],tb[MAXN],c[MAXN],*x,*y; x=ta; y=tb;
    	for(rint i=0;i<M;i++) c[i]=0;
    	for(rint i=0;i<N;i++) c[x[i]=S[i]]++;
    	for(rint i=1;i<M;i++) c[i]+=c[i-1];
    	for(rint i=N-1;i>=0;i--) sa[--c[x[i]]]=i;	
    	for(rint k=1;k<N;k<<=1){
    		int p=0;
    		for(rint i=N-k;i<N;i++) y[p++]=i;
    		for(rint i=0;i<N;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
    		for(rint i=0;i<M;i++) c[i]=0;
    		for(rint i=0;i<N;i++) c[x[y[i]]]++;
    		for(rint i=1;i<M;i++) c[i]+=c[i-1];
    		for(rint i=N-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
    		swap(x,y); y[N]=-1; M=1; x[sa[0]]=0;
    		for(rint i=1;i<N;i++)
    			x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?M-1:M++;
    		if(M>=N) break;
    	}
    	for(rint i=0;i<N;i++) rak[sa[i]+1]=i+1;
    	for(rint i=0,h=0,j;i<N;i++){
    		if(h) h--;
    		if(rak[i+1]>1){
    			j=sa[(rak[i+1]-1)-1];
    			while(S[i+h]==S[j+h]) h++;
    		}
    		stm[rak[i+1]][0]=hei[rak[i+1]]=h;
    	}
    	for(rint k=1;k<=log2[N];k++)
    		for(rint i=(1<<k);i<=N;i++)
    			stm[i][k]=min(stm[i-(1<<(k-1))][k-1],stm[i][k-1]);
    }
    int LCP(int l,int r){
    	if(l>r) swap(l,r); l++;
    	int k=log2[r-l+1];
    	return min(stm[l+(1<<k)-1][k],stm[r][k]);
    }
    int multiply_find(int p,int x,int y,int N){
    	int q=p;
    	for(rint k=log2[N],Q;k>=0;k--){
    		Q=q+(1<<k)*y;
    		if(Q<1||Q>N) continue;
    		if(LCP(Q,p)<x) continue;
    		q=Q;
    	}
    	return q;
    }
    bool check(int x,int a,int b,int c,int d,int N){
    	int L=multiply_find(rak[c],x,-1,N);
    	int R=multiply_find(rak[c],x,1,N);
    	int Lu=a-1,Ru=b-x+1;
    	return T.query(T.rt[Lu],T.rt[Ru],1,N,L,R);
    }
    int binary_ans(int l,int r,int a,int b,int c,int d,int N){
    	int mid,ans=0;
    	while(l<=r){
    		mid=(l+r)>>1;
    		if(check(mid,a,b,c,d,N)) ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	return ans;
    }
    int main()
    {
    	//filein(str); fileout(str);
    	log2[1]=0;
    	for(rint i=2;i<=100000;i++) log2[i]=log2[i>>1]+1;
    	int N,M,a,b,c,d;
    	scanf("%d%d",&N,&M);
    	scanf("%s",S); build(N,300);
    	T.reset(T.rt[0],1,N);
    	for(rint i=0;i<N;i++)
    		T.build(T.rt[i+1],1,N,rak[i+1],T.rt[i]);
    	for(rint i=1,ans;i<=M;i++){ 
    		scanf("%d%d%d%d",&a,&b,&c,&d);
    		if(a>b) swap(a,b); if(c>d) swap(c,d);
    		ans=binary_ans(1,min(d-c+1,b-a+1),a,b,c,d,N);
    		printf("%d
    ",ans);
    	} 
    	return 0;
    }

     

  • 相关阅读:
    ASP.NET购物车Cookie获取,创建,添加,更新,删除的用法
    python-列表常用功能介绍
    Java并发编程(一)
    《How Tomcat Works》读书笔记(三)--Connector(连接器)
    好了歌
    《How Tomcat Works》读书笔记(二)
    《Head First Servlet&JSP》读书笔记
    J2EE思考
    《Spring实战》读书笔记--使用SpringMVC构建REST API
    HTTP协议(一)
  • 原文地址:https://www.cnblogs.com/zj75211/p/7978815.html
Copyright © 2020-2023  润新知