• BZOJ 4556 [Tjoi2016&Heoi2016]字符串


    题解:

    神题

    我们二分一个答案k

    在(a,b-k+1)中找一个与c的最长公公前缀

    从c在rank数组中的位置向两边扩展直到min<k,边界(l,r)

    然后在(l,r)中找到有没有(a,b-k+1)中的元素,主席树实现,差分

    一但找到立刻return;

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 const int maxn=200009;
      8 
      9 int n,TT;
     10 char s[maxn];
     11 
     12 int t1[maxn],t2[maxn];
     13 int c[maxn],sa[maxn];
     14 void BuildSA(int m){
     15     int *x=t1,*y=t2;
     16     
     17     for(int i=1;i<=m;++i)c[i]=0;
     18     for(int i=1;i<=n;++i)c[x[i]=s[i]]++;
     19     for(int i=2;i<=m;++i)c[i]+=c[i-1];
     20     for(int i=n;i>=1;--i)sa[c[x[i]]--]=x[i];
     21     
     22     for(int k=1;k<n;k<<=1){
     23         int p=0;
     24         for(int i=n-k+1;i<=n;++i)y[++p]=i;
     25         for(int i=1;i<=n;++i)if(sa[i]>k)y[++p]=sa[i]-k;
     26         
     27         for(int i=1;i<=m;++i)c[i]=0;
     28         for(int i=1;i<=n;++i)c[x[y[i]]]++;
     29         for(int i=2;i<=m;++i)c[i]+=c[i-1];
     30         for(int i=n;i>=1;--i)sa[c[x[y[i]]]--]=y[i];
     31         
     32         swap(x,y);
     33         x[sa[1]]=p=1;
     34         for(int i=2;i<=n;++i){
     35             if((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+k]==y[sa[i-1]+k]))p:++p;
     36         }
     37         if(p>=n)break;
     38         m=p;
     39     }
     40 }
     41 
     42 int rk[maxn],ht[maxn];
     43 void GetHeight(){
     44     int k=0;
     45     for(int i=1;i<=n;++i)rk[sa[i]]=i;
     46     
     47     for(int i=1;i<=n;++i){
     48         if(k)--k;
     49         int j=sa[rk[i]-1];
     50         while(s[i+k]==s[j+k])++k;
     51         ht[rk[i]]=k;
     52     }
     53 }
     54 
     55 int PTsiz=0;
     56 int root[maxn];
     57 struct SegmentTree{
     58     int l,r,d,ls,rs;
     59 }tree[maxn*30];
     60 void BuildTree(int &now,int l,int r){
     61     now=++PTsiz;
     62     tree[now].l=l;tree[now].r=r;tree[now].d=0;
     63     if(l==r)return;
     64     int mid=(l+r)>>1;
     65     BuildTree(tree[now].ls,l,mid);
     66     BuildTree(tree[now].rs,mid+1,r);
     67 }
     68 void Updatapoint(int &now,int pre,int pla){
     69     now=++PTsiz;
     70     tree[now]=tree[pre];
     71     tree[now].d++;
     72     if(tree[now].l==tree[now].r)return;
     73     int mid=(tree[now].l+tree[now].r)>>1;
     74     if(pla<=mid)Updatapoint(tree[now].ls,tree[pre].ls,pla);
     75     else Updatapoint(tree[now].rs,tree[pre].rs,pla);
     76 }
     77 int Querysum(int now,int pre,int ll,int rr){
     78     if(tree[now].l>=ll&&tree[now].r<=rr){
     79         int d=tree[now].d-tree[pre].d;
     80         if(d)return 1;
     81         else return 0;
     82     }
     83     int mid=(tree[now].l+tree[now].r)>>1;
     84     int ret=0;
     85     if(ll<=mid)ret=Querysum(tree[now].ls,tree[pre].ls,ll,rr);
     86     if(rr>mid)ret|=Querysum(tree[now].rs,tree[pre].rs,ll,rr);
     87     return ret;
     88 }
     89 
     90 int f[maxn][20];
     91 int ds[maxn];
     92 void STinit(){
     93     for(int i=1;i<=n;++i)f[i][0]=ht[i];
     94     for(int j=1;j<=19;++j){
     95         for(int i=1;i+(1<<j)-1<=n;++i){
     96             f[i][j]=min(f[i][j-1],f[i+(1<<j)][j-1]);
     97         }
     98     }
     99 }
    100 int Querymin(int l,int r){
    101     int k=ds[r-l+1];
    102     return min(f[l][k],f[r-(1<<k)+1][k]);
    103 }
    104 
    105 int l_bound(int l,int r,int c,int len){
    106     int mid,ans=c;
    107     while(l<=r){
    108         mid=(l+r)>>1;
    109         if(Querymin(mid+1,c)>=len){
    110             ans=mid;r=mid-1;
    111         }else{
    112             l=mid+1;
    113         }
    114     }
    115     return ans;
    116 }
    117 int r_bound(int l,int r,int c,int len){
    118     int mid,ans=c;
    119     while(l<=r){
    120         mid=(l+r)>>1;
    121         if(Querymin(c+1,mid)>=len){
    122             ans=mid;l=mid+1;
    123         }else{
    124             r=mid-1;
    125         }
    126     }
    127     return ans;
    128 }
    129 
    130 int Getans(int ll,int rr,int c,int d){
    131     int pla=rk[c];
    132     int l=0,r=min(rr-ll+1,d-c+1),mid,ans=0;
    133     while(l<=r){
    134         mid=(l+r)>>1;
    135         int tl=l_bound(1,pla-1,c,mid);
    136         int tr=r_bound(pla+1,n,c,mid);
    137         if(Querysum(root[tr],root[tl-1],ll,rr-mid+1)){
    138             ans=mid;
    139             l=mid+1;
    140         }else{
    141             r=mid-1;
    142         }
    143     }
    144     return ans;
    145 }
    146 
    147         
    148 int main(){
    149     scanf("%d%d",&n,&TT);
    150     scanf("%s",s+1);
    151     BuildSA(200);
    152     GetHeight();
    153     BuildTree(root[0],1,n);
    154     for(int i=1;i<=n;++i)Updatapoint(root[i],root[i-1],sa[i]);
    155     for(int i=1;i<=n;++i)ds[i]=log2(i+0.5);
    156     STinit();
    157     
    158     while(TT--){
    159         int a,b,c,d;
    160         scanf("%d%d%d%d",&a,&b,&c,&d);
    161         printf("%d
    ",(Getans(a,b,c,d)));
    162     }
    163     return 0;
    164 }
    自己还是太辣鸡了
  • 相关阅读:
    Selenium2Library+ride学习笔记
    windbg 调试技巧
    LINUX常用命令--重定向、管道篇(四)
    Linux文件系统与结构
    windbg命令学习4
    windbg命令学习3
    windbg命令学习2
    MySQL常用操作命令
    Httpwatch 工具介绍
    windows平台上用python 远程线程注入,执行shellcode
  • 原文地址:https://www.cnblogs.com/zzyer/p/8620036.html
Copyright © 2020-2023  润新知