zoukankan      html  css  js  c++  java
  • ●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;
    }

     

  • 相关阅读:
    Leetcode Unique Binary Search Trees
    Leetcode Decode Ways
    Leetcode Range Sum Query 2D
    Leetcode Range Sum Query
    Leetcode Swap Nodes in Pairs
    Leetcode Rotate Image
    Leetcode Game of Life
    Leetcode Set Matrix Zeroes
    Leetcode Linked List Cycle II
    CF1321A
  • 原文地址:https://www.cnblogs.com/zj75211/p/7978815.html
Copyright © 2011-2022 走看看