• HDU


    题意:给你一个长度为n的字符串和m组询问,每组询问给出l,r,k,求s[l,r]的第k次出现的左端点。

    解法一:

    求出后缀数组,按照排名建主席树,对于每组询问二分或倍增找出主席树上所对应的的左右端点,求第k大的下标即可。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N=1e5+10,mod=998244353;
     5 char buf[N];
     6 int s[N],sa[N],buf1[N],buf2[N],c[N],n,rnk[N],ht[N],ST[N][20],Log[N],m;
     7 void Sort(int* x,int* y,int m) {
     8     for(int i=0; i<m; ++i)c[i]=0;
     9     for(int i=0; i<n; ++i)++c[x[i]];
    10     for(int i=1; i<m; ++i)c[i]+=c[i-1];
    11     for(int i=n-1; i>=0; --i)sa[--c[x[y[i]]]]=y[i];
    12 }
    13 void da(int* s,int n,int m=1000) {
    14     int *x=buf1,*y=buf2;
    15     x[n]=y[n]=-1;
    16     for(int i=0; i<n; ++i)x[i]=s[i],y[i]=i;
    17     Sort(x,y,m);
    18     for(int k=1; k<n; k<<=1) {
    19         int p=0;
    20         for(int i=n-k; i<n; ++i)y[p++]=i;
    21         for(int i=0; i<n; ++i)if(sa[i]>=k)y[p++]=sa[i]-k;
    22         Sort(x,y,m),p=1,y[sa[0]]=0;
    23         for(int i=1; i<n; ++i)y[sa[i]]=x[sa[i-1]]==x[sa[i]]&&x[sa[i-1]+k]==x[sa[i]+k]?p-1:p++;
    24         if(p==n)break;
    25         swap(x,y),m=p;
    26     }
    27 }
    28 void getht() {
    29     for(int i=0; i<n; ++i)rnk[sa[i]]=i;
    30     ht[0]=0;
    31     for(int i=0,k=0; i<n; ++i) {
    32         if(k)--k;
    33         if(!rnk[i])continue;
    34         for(; s[i+k]==s[sa[rnk[i]-1]+k]; ++k);
    35         ht[rnk[i]]=k;
    36     }
    37 }
    38 void initST() {
    39     for(int i=1; i<n; ++i)ST[i][0]=ht[i];
    40     for(int j=1; (1<<j)<=n; ++j)
    41         for(int i=1; i+(1<<j)-1<n; ++i)
    42             ST[i][j]=min(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
    43 }
    44 int lcp(int l,int r) {
    45     if(l==r)return n-sa[l];
    46     if(l>r)swap(l,r);
    47     l++;
    48     int k=Log[r-l+1];
    49     return min(ST[l][k],ST[r-(1<<k)+1][k]);
    50 }
    51 int rt[N],ls[N*30],rs[N*30],sum[N*30],tot;
    52 #define mid ((l+r)>>1)
    53 int cpy(int v) {int u=++tot; ls[u]=ls[v],rs[u]=rs[v],sum[u]=sum[v]; return u;}
    54 void upd(int& u,int v,int p,int l=0,int r=n-1) {
    55     u=cpy(v);
    56     sum[u]++;
    57     if(l==r)return;
    58     p<=mid?upd(ls[u],ls[v],p,l,mid):upd(rs[u],rs[v],p,mid+1,r);
    59 }
    60 int qry(int u,int v,int k,int l=0,int r=n-1) {
    61     if(l==r)return l;
    62     int cnt=sum[ls[u]]-sum[ls[v]];
    63     return k<=cnt?qry(ls[u],ls[v],k,l,mid):qry(rs[u],rs[v],k-cnt,mid+1,r);
    64 }
    65 void build() {
    66     da(s,n),getht(),initST();
    67     tot=0;
    68     for(int i=1; i<=n; ++i)upd(rt[i],rt[i-1],sa[i-1]);
    69 }
    70 int main() {
    71     Log[0]=-1;
    72     for(int i=1; i<N; ++i)Log[i]=Log[i>>1]+1;
    73     int T;
    74     for(scanf("%d",&T); T--;) {
    75         scanf("%d%d%s",&n,&m,buf);
    76         for(int i=0; i<n; ++i)s[i]=buf[i];
    77         s[n]=0;
    78         build();
    79         while(m--) {
    80             int l,r,k;
    81             scanf("%d%d%d",&l,&r,&k);
    82             l--,r--;
    83             int L,R,M=rnk[l],len=r-l+1;
    84             L=R=M;
    85             for(int i=Log[n]; i>=0; --i)if(L-(1<<i)>=0&&lcp(M,L-(1<<i))>=len)L-=(1<<i);
    86             for(int i=Log[n]; i>=0; --i)if(R+(1<<i)<n&&lcp(M,R+(1<<i))>=len)R+=(1<<i);
    87             printf("%d
    ",k<=sum[rt[R+1]]-sum[rt[L]]?qry(rt[R+1],rt[L],k)+1:-1);
    88         }
    89     }
    90     return 0;
    91 }

    解法二:

    建立后缀自动机,对后缀树(fail树)作线段树合并可得到每个结点包含的全部right值。对每个询问倍增找到待查询子串所对应的结点,然后线段树上查询第k大即可。

    可持久化合并可以实现在线查询。

    fail树上dfs序建可持久化线段树貌似也可以(这句话怎么这么耳熟?)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int N=2e5+10,M=26;
     5 char s[N];
     6 int n,m,fa[N],go[N][M],mxl[N],last,tot,samrt[N],c[N],ss[N],Fa[N][20];
     7 int rt[N],ls[N*50],rs[N*50],sum[N*50],tot2;
     8 #define mid ((l+r)>>1)
     9 int cpy(int v) {int u=++tot2; ls[u]=ls[v],rs[u]=rs[v],sum[u]=sum[v]; return u;}
    10 void upd(int& u,int v,int p,int l=1,int r=n) {
    11     u=cpy(v),sum[u]++;
    12     if(l==r)return;
    13     p<=mid?upd(ls[u],ls[v],p,l,mid):upd(rs[u],rs[v],p,mid+1,r);
    14 }
    15 void mg(int& w,int u,int v) {
    16     if(!u||!v) {w=u|v; return;}
    17     w=cpy(u),sum[w]+=sum[v];
    18     mg(ls[w],ls[u],ls[v]),mg(rs[w],rs[u],rs[v]);
    19 }
    20 int qry(int u,int k,int l=1,int r=n) {
    21     if(l==r)return l;
    22     return k<=sum[ls[u]]?qry(ls[u],k,l,mid):qry(rs[u],k-sum[ls[u]],mid+1,r);
    23 }
    24 int newnode(int l) {int u=++tot; rt[u]=0,mxl[u]=l,memset(go[u],0,sizeof go[u]); return u;}
    25 void add(int ch,int r) {
    26     int p=last,np=last=newnode(mxl[p]+1);
    27     samrt[r]=np;
    28     upd(rt[np],rt[np],r,1);
    29     for(; p&&!go[p][ch]; p=fa[p])go[p][ch]=np;
    30     if(!p)fa[np]=1;
    31     else {
    32         int q=go[p][ch];
    33         if(mxl[q]==mxl[p]+1)fa[np]=q;
    34         else {
    35             int nq=newnode(mxl[p]+1);
    36             memcpy(go[nq],go[q],sizeof go[q]);
    37             fa[nq]=fa[q],fa[q]=fa[np]=nq;
    38             for(; p&&go[p][ch]==q; p=fa[p])go[p][ch]=nq;
    39         }
    40     }
    41 }
    42 void build() {
    43     tot=tot2=0,last=newnode(0);
    44     for(int i=0; i<n; ++i)add(s[i]-'a',i+1);
    45     for(int i=0; i<=tot; ++i)c[i]=0;
    46     for(int i=1; i<=tot; ++i)++c[mxl[i]];
    47     for(int i=1; i<=tot; ++i)c[i]+=c[i-1];
    48     for(int i=1; i<=tot; ++i)ss[--c[mxl[i]]]=i;
    49     for(int i=tot-1; i>0; --i)mg(rt[fa[ss[i]]],rt[fa[ss[i]]],rt[ss[i]]);
    50     for(int i=1; i<=tot; ++i)Fa[i][0]=fa[i];
    51     for(int k=1; k<20; ++k)for(int i=1; i<=tot; ++i)Fa[i][k]=Fa[Fa[i][k-1]][k-1];
    52 }
    53 int main() {
    54     int T;
    55     for(scanf("%d",&T); T--;) {
    56         scanf("%d%d%s",&n,&m,s);
    57         build();
    58         while(m--) {
    59             int l,r,k;
    60             scanf("%d%d%d",&l,&r,&k);
    61             int u=samrt[r],len=r-l+1;
    62             if(mxl[fa[u]]+1>len) {
    63                 for(int k=19; k>=0; --k)if(mxl[fa[Fa[u][k]]]+1>len)u=Fa[u][k];
    64                 u=fa[u];
    65             }
    66             printf("%d
    ",k<=sum[rt[u]]?qry(rt[u],k)-len+1:-1);
    67         }
    68     }
    69     return 0;
    70 }
  • 相关阅读:
    Golang 之 casbin(权限管理)
    Golang validate验证器
    商城实战课程
    webstorm上的Element提示插件
    实战高并发大流量秒杀系统
    lettcode 739: 每日温度
    时钟同步 chrony
    linux 文件目录权限命令
    Nginx 四层负载均衡
    Nginx 版本回滚
  • 原文地址:https://www.cnblogs.com/asdfsag/p/11515433.html
Copyright © 2020-2023  润新知