• BZOJ4556: [Tjoi2016&Heoi2016]字符串


    Description

    佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了
    一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CE
    O,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公
    共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?

    Input

    输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来
    m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,
    字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=n
     

    Output

     对于每一次询问,输出答案。

    Sample Input

    5 5
    aaaaa
    1 1 1 5
    1 5 1 1
    2 3 2 3
    2 4 2 3
    2 3 2 4

    Sample Output

    1
    1
    2
    2
    2
     
    考虑将串逆序后使用后缀自动机来做,对于每个询问我们可以二分一下答案len,然后倍增到SAM上的对应节点,这是我们发现只要判断该节点的right集中是否包含[a,b-len+1]中的元素即可。这个用棵线段树合并什么的东西预处理一下每个节点的right集就好了,时间复杂度为O(Nlog^2N)。
    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=200010;
    const int maxnode=4000010;
    int n,m,root[maxn],pos[maxn],c[maxn],od[maxn];
    int ls[maxnode],rs[maxnode],ToT;
    int to[maxn][26],anc[maxn][20],l[maxn],fa[maxn],cnt=1,last=1;
    void insert(int& y,int l,int r,int p) {
    	y=++ToT;if(l==r) return;int mid=l+r>>1;
    	if(p<=mid) insert(ls[y],l,mid,p);
    	else insert(rs[y],mid+1,r,p);
    }
    int merge(int x,int y) {
    	if(!x) return y;
    	if(!y) return x;
    	int z=++ToT;
    	ls[z]=merge(ls[x],ls[y]);
    	rs[z]=merge(rs[x],rs[y]);
    	return z;
    }
    int query(int x,int l,int r,int ql,int qr) {
    	if(!x) return 0;
    	if(ql<=l&&r<=qr) return 1;
    	int mid=l+r>>1;
    	if(ql<=mid&&query(ls[x],l,mid,ql,qr)) return 1;
    	if(qr>mid&&query(rs[x],mid+1,r,ql,qr)) return 1;
    }
    void extend(int c,int val) {
    	int p=last,q,np,nq;l[last=np=++cnt]=l[p]+1;
    	insert(root[np],1,n,val);pos[val]=np;
    	for(;!to[p][c];p=fa[p]) to[p][c]=np;
    	if(!p) fa[np]=1;
    	else {
    		q=to[p][c];
    		if(l[p]+1==l[q]) fa[np]=q;
    		else {
    			l[nq=++cnt]=l[p]+1;
    			fa[nq]=fa[q];fa[q]=fa[np]=nq;
    			memcpy(to[nq],to[q],sizeof(to[q]));
    			for(;to[p][c]==q;p=fa[p]) to[p][c]=nq;
    		}
    	}
    }
    char str[maxn];
    int check(int x,int a,int b,int p) {
    	dwn(i,19,0) if(x<=l[anc[p][i]]) p=anc[p][i];
    	return query(root[p],1,n,a,b-x+1);
    }
    int main() {
    	n=read();m=read();
    	scanf("%s",str+1);
    	dwn(i,n,1) extend(str[i]-'a',i);
    	rep(i,1,cnt) c[l[i]]++;
    	rep(i,1,n) c[i]+=c[i-1];
    	dwn(i,cnt,1) od[c[l[i]]--]=i;
    	dwn(i,cnt,1) root[fa[od[i]]]=merge(root[fa[od[i]]],root[od[i]]);
    	rep(i,1,cnt) {
    		int x=od[i];anc[x][0]=fa[x];
    		rep(j,1,19) anc[x][j]=anc[anc[x][j-1]][j-1];
    	}
    	while(m--) {
    		int a=read(),b=read(),x=read(),y=read();
    		int l=0,r=min(y-x+1,b-a+1)+1,mid;
    		while(l+1<r) if(check(mid=l+r>>1,a,b,pos[x])) l=mid; else r=mid;
    		printf("%d
    ",l);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    python2代码改成python3踩过的坑
    Mac下为什么有的文件名后带一个* 星号?
    Mac 的 Vim 中 delete 键失效的原因和解决方案(转)
    使用pandas处理大型CSV文件(转)
    Java基础——02
    javaee相关基础
    Cookie&Session笔记
    EL&JSTL笔记------jsp
    JavaWeb基础
    Java基础——01
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5502925.html
Copyright © 2020-2023  润新知