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

      

  • 相关阅读:
    autocomplete自动完成搜索提示仿google提示效果
    实现子元素相对于父元素左右居中
    javascript 事件知识集锦
    让 IE9 以下的浏览器支持 Media Queries
    「2013124」Cadence ic5141 installation on CentOS 5.5 x86_64 (limited to personal use)
    「2013420」SciPy, Numerical Python, matplotlib, Enthought Canopy Express
    「2013324」ClipSync, Youdao Note, GNote
    「2013124」XDMCP Configuration for Remote Access to Linux Desktop
    「2013115」Pomodoro, Convert Multiple CD ISO to One DVD ISO HowTo.
    「2013123」CentOS 5.5 x86_64 Installation and Configuration (for Univ. Labs)
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5502925.html
Copyright © 2011-2022 走看看