zoukankan      html  css  js  c++  java
  • [BZOJ4556][TJOI2016&&HEOI2016]字符串

    bzoj
    luogu

    sol

    我不得不说这道题很码。。。
    (lcp)的话当然先来一发后缀数组+ST表。
    可以二分一个答案(mid),可知序列中与(c)(lcp)大于等于(mid)的后缀肯定是(Rank)上的连续一段。
    再二分一下找出这一段的左端点和右端点,设为([up,down]),然后问题相当于转化成了:是否存在(iin[a,b])使得(Rank[i]in[up,down])
    也就是给一个矩形问上面有没有点?直接主席树查询即可。
    主席树其实可以看作是,维护了(n)个在(n*n)二维平面上的点。
    复杂度是(O(mlog^{2}{n}))。交完之后是能感叹自己常数太大。

    code

    #include<cstdio>
    #include<algorithm>
    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;
    char s[N];
    int n,m,a[N],T[N],X[N],Y[N],SA[N],Rank[N],Height[19][N],lg[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]=a[i]];
    	for (int i=1;i<=m;++i) T[i]+=T[i-1];
    	for (int i=n;i>=1;--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>=1;--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 (a[i+j]==a[SA[Rank[i]-1]+j]) ++j;
    		Height[0][Rank[i]]=j;
    	}
    	for (int j=1;j<19;++j)
    		for (int i=1;i+(1<<j-1)<=n;++i)
    			Height[j][i]=min(Height[j-1][i],Height[j-1][i+(1<<j-1)]);
    }
    struct president_tree{int ls,rs,sum;}t[N*40];int rt[N],tot;
    void modify(int &x,int l,int r,int p)
    {
    	t[++tot]=t[x];t[x=tot].sum++;
    	if (l==r) return;int mid=l+r>>1;
    	if (p<=mid) modify(t[x].ls,l,mid,p);
    	else modify(t[x].rs,mid+1,r,p);
    }
    int query(int A,int B,int l,int r,int ql,int qr)
    {
    	if (l>=ql&&r<=qr) return t[B].sum-t[A].sum;
    	int mid=l+r>>1,s=0;
    	if (ql<=mid) s+=query(t[A].ls,t[B].ls,l,mid,ql,qr);
    	if (qr>mid) s+=query(t[A].rs,t[B].rs,mid+1,r,ql,qr);
    	return s;
    }
    int lcp(int l,int r)
    {
    	if (l==r) return (int)1e9;
    	++l;int k=lg[r-l+1];
    	return min(Height[k][l],Height[k][r-(1<<k)+1]);
    }
    bool check(int MID,int x,int y,int u)
    {
    	int l,r,up,down;
    	l=1;r=Rank[u];
    	while (l<r)
    	{
    		int mid=l+r>>1;
    		if (lcp(mid,Rank[u])>=MID) r=mid;
    		else l=mid+1;
    	}
    	up=l;
    	l=Rank[u];r=n;
    	while (l<r)
    	{
    		int mid=l+r+1>>1;
    		if (lcp(Rank[u],mid)>=MID) l=mid;
    		else r=mid-1;
    	}
    	down=l;
    	return query(rt[up-1],rt[down],1,n,x,y-MID+1);
    }
    int main()
    {
    	n=gi();m=gi();lg[0]=-1;
    	for (int i=1;i<=n;++i) lg[i]=lg[i>>1]+1;
    	scanf("%s",s+1);
    	for (int i=1;i<=n;++i) a[i]=s[i]-'a'+1;
    	getSA();
    	for (int i=1;i<=n;++i) rt[i]=rt[i-1],modify(rt[i],1,n,SA[i]);
    	while (m--)
    	{
    		int x=gi(),y=gi(),u=gi(),v=gi();
    		int l=0,r=min(y-x+1,v-u+1);
    		while (l<r)
    		{
    			int mid=l+r+1>>1;
    			if (check(mid,x,y,u)) l=mid;
    			else r=mid-1;
    		}
    		printf("%d
    ",l);
    	}
    	return 0;
    }
    
  • 相关阅读:
    LeetCode Best Time to Buy and Sell Stock
    LeetCode Scramble String
    LeetCode Search in Rotated Sorted Array II
    LeetCode Gas Station
    LeetCode Insertion Sort List
    LeetCode Maximal Rectangle
    Oracle procedure
    浏览器下载代码
    Shell check IP
    KVM- 存储池配置
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8467518.html
Copyright © 2011-2022 走看看