zoukankan      html  css  js  c++  java
  • bzoj 4556: [Tjoi2016&Heoi2016]字符串

    Description

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

    Solution

    二分答案
    那么只需要判定 (s[c,c+mid-1]) 是否在 ([a+mid-1,b]) 出现过
    找到串 (s[c,c+mid-1]) 对应的节点,查一下子树内的 (pos) 集合是否存在 ([a+mid-1,b])
    找到对应节点,通过前缀 (s[1,c+mid-1]) 倍增跳就可以了,(pos) 集合用线段树维护一下就行了

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=2e5+10;
    int n,Q,ch[N][26],len[N],fa[N],cur=1,cnt=1,pos[N],tt=0,a,b,c,d,f[N][20];
    char s[N];int ls[N*30],rs[N*30],head[N],nxt[N],to[N],num=0,rt[N];
    inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    inline void ins(int c){
    	int p=cur;cur=++cnt;len[cur]=len[p]+1;
    	for(;p && !ch[p][c];p=fa[p])ch[p][c]=cur;
    	if(!p)fa[cur]=1;
    	else{
    		int q=ch[p][c];
    		if(len[p]+1==len[q])fa[cur]=q;
    		else{
    			int nt=++cnt;len[nt]=len[p]+1;
    			memcpy(ch[nt],ch[q],sizeof(ch[q]));
    			fa[nt]=fa[q];fa[q]=fa[cur]=nt;
    			for(;p && ch[p][c]==q;p=fa[p])ch[p][c]=nt;
    		}
    	}
    }
    inline void ins(int &x,int l,int r,int sa){
    	if(!x)x=++tt;
    	if(l==r)return ;
    	int mid=(l+r)>>1;
    	if(sa<=mid)ins(ls[x],l,mid,sa);
    	else ins(rs[x],mid+1,r,sa);
    }
    inline int merge(int x,int y){
    	if(!x||!y)return x+y;
    	int o=++tt;
    	ls[o]=merge(ls[x],ls[y]);
    	rs[o]=merge(rs[x],rs[y]);
    	return o;
    }
    inline void dfs(int x){
    	for(int i=head[x];i;i=nxt[i])dfs(to[i]),rt[x]=merge(rt[x],rt[to[i]]);
    }
    inline bool qry(int x,int l,int r,int sa,int se){
    	if(!x)return 0;
    	if(sa<=l && r<=se)return 1;
    	int mid=(l+r)>>1;
    	if(se<=mid)return qry(ls[x],l,mid,sa,se);
    	if(sa>mid)return qry(rs[x],mid+1,r,sa,se);
    	return qry(ls[x],l,mid,sa,mid)|qry(rs[x],mid+1,r,mid+1,se);
    }
    inline bool check(int mid,int r){
    	int x=pos[r];
    	for(int i=19;i>=0;i--)
    		if(f[x][i] && len[f[x][i]]>=mid)x=f[x][i];
    	return qry(rt[x],1,n,a+mid-1,b);
    }
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      cin>>n>>Q;
      scanf("%s",s+1);
      for(int i=1;i<=n;i++)ins(s[i]-'a'),ins(rt[cur],1,n,i),pos[i]=cur;
      for(int i=2;i<=cnt;i++)link(fa[i],i);
      for(int i=1;i<=cnt;i++)f[i][0]=fa[i];
      for(int j=1;j<20;j++)
    	  for(int i=1;i<=cnt;i++)f[i][j]=f[f[i][j-1]][j-1];
      dfs(1);
      while(Q--){
    	  gi(a);gi(b);gi(c);gi(d);
    	  int l=1,r=min(b-a+1,d-c+1),mid,ret=0;
    	  while(l<=r){
    		  mid=(l+r)>>1;
    		  if(check(mid,c+mid-1))ret=mid,l=mid+1;
    		  else r=mid-1;
    	  }
    	  printf("%d
    ",ret);
      }
      return 0;
    }
    
    
  • 相关阅读:
    秋叶收藏集, LC个人竞赛题目解析
    字典树,前缀树的模板!秒懂
    106. 从中序与后序遍历序列构造二叉树
    c++ enum 的枚举
    c++变量的声明和定义
    leetcode 39 组合总数(回溯)
    python lambda表达式应用
    python解压可迭代对象赋值给多个变量
    python之解压序列并赋值给变量
    Python循环列表的方法
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8891647.html
Copyright © 2011-2022 走看看