洛谷 5284 [十二省联考2019]字符串问题——后缀数组+线段树优化连边+真实字典序排序思路

题目:https://www.luogu.org/problemnew/show/P5284

每个 b 找出它是哪些 a 的前缀,然后就可以让一些 a 向另一些 a 连边,这个图找最长路即可。

b 找它是哪些 a 的前缀的时候,可以做出后缀数组,然后二分一下 LCP >= lenb 的范围,范围内的 a 就是可以连边的(如果 |a|>=|b|)。

边数可能 n2 ,但注意到一个 b 导致的连边是一个区间内的 a ,所以考虑线段树优化连边。

但考场上觉得太难写了,就只写了暴力连边的 40 分。结果得了 0 分。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
#define pb push_back
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
ll Mx(ll a,ll b){return a>b?a:b;}
ll Mn(ll a,ll b){return a<b?a:b;}
const int N=2e5+5;
char s[N]; int na,nb;
namespace S1{
  const int M=1005,K=15,M2=M*M;
  int n,sa[N],rk[N],tp[N],tx[30],ht[N][K],lg[N],bin[K];
  int hd[M],xnt,to[M2],nxt[M2],w[M2]; ll dis[M];
  int rd[N]; bool vis[M],ins[M],flag;
  struct Node{
    int l,r;
    bool operator< (const Node &b)const
    {return r==b.r?l>b.l:r<b.r;}
  }a[M],b[M],fw[M],sta[M];
  vector<Node> vt[M];
  queue<int> q;
  void init()
  {
    xnt=0;for(int i=1;i<=na;i++)hd[i]=rd[i]=0;
    flag=0;for(int i=1;i<=na;i++)vis[i]=ins[i]=0;
    for(int i=1;i<=na;i++)vt[i].clear();//
  }
  void add(int x,int y,int z)
  {to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;rd[y]++;}
  void Rsort(int n,int nm)
  {
    for(int i=1;i<=nm;i++)tx[i]=0;
    for(int i=1;i<=n;i++)tx[rk[i]]++;
    for(int i=2;i<=nm;i++)tx[i]+=tx[i-1];
    for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
  }
  void get_sa(int n,int nm)
  {
    for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1,tp[i]=i;
    Rsort(n,nm);
    for(int k=1;k<=n;k<<=1)
      {
    int tot=0;
    for(int i=n-k+1;i<=n;i++)tp[++tot]=i;
    for(int i=1;i<=n;i++)
      if(sa[i]>k)tp[++tot]=sa[i]-k;
    Rsort(n,nm);
    for(int i=1;i<=n;i++)tp[i]=rk[i];
    rk[sa[1]]=nm=1;
    for(int i=2;i<=n;i++)
      {
        int u=sa[i]+k,v=sa[i-1]+k; if(u>n)u=0;if(v>n)v=0;
        rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[u]==tp[v])?nm:++nm;
      }
    if(nm==n)break;
      }
  }
  void get_ht(int n)
  {
    for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
    bin[0]=1;
    for(int i=1;i<=lg[n];i++)bin[i]=bin[i-1]<<1;
    for(int i=1,k=0,j;i<=n;i++)//k=0
      {
    for((k?k--:0),j=sa[rk[i]-1];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
    ht[rk[i]][0]=k;
      }
    for(int t=1;t<=lg[n];t++)
      for(int i=1;i+bin[t]-1<=n;i++)
    ht[i][t]=Mn(ht[i][t-1],ht[i+bin[t-1]][t-1]);
  }
  int qry_ht(int l,int r)
  {
    if(l==r)return n-sa[l]+1;
    if(l>r)swap(l,r); l++; int d=lg[r-l+1];
    return Mn(ht[l][d],ht[r-bin[d]+1][d]);
  }
  void solve2()
  {
    int m=rdn();
    while(m--)rdn(), rdn();
    int cr=rk[a[1].l];
    for(int i=1;i<=nb;i++)
      if(qry_ht(cr,b[i].l)>=b[i].r-b[i].l+1)
    {flag=1;break;}
    if(flag)puts("-1"); else printf("%d\n",a[1].r-a[1].l+1);
  }
  Node cz(int p,int len)
  {
    Node ret; p=rk[p];//rk
    int l=1,r=p,ans=p;
    while(l<=r)
      {
    int mid=l+r>>1;
    if(qry_ht(mid,p)>=len)ans=mid,r=mid-1;
    else l=mid+1;
      }
    ret.l=ans;
    l=p; r=n; ans=p;
    while(l<=r)
      {
    int mid=l+r>>1;
    if(qry_ht(mid,p)>=len)ans=mid,l=mid+1;
    else r=mid-1;
      }
    ret.r=ans; return ret;
  }
  void sol(int bh)
  {
    sort(vt[bh].begin(),vt[bh].end());
    int top=0;
    for(int i=0,lm=vt[bh].size();i<lm;i++)
      {
    while(top&&sta[top].l>=vt[bh][i].l)top--;
    if(!top||sta[top].r<vt[bh][i].l)
      { sta[++top]=vt[bh][i];continue;}
    sta[top].r=vt[bh][i].r;
      }
    for(int i=1;i<=top;i++)
      for(int j=sta[i].l;j<=sta[i].r;j++)vis[j]=1;
    for(int i=1;i<=na;i++)
      if(vis[rk[a[i].l]])add(bh,i,a[i].r-a[i].l+1);
    memset(vis,0,sizeof vis);
  }
  void dfs(int cr)
  {
    vis[cr]=1;ins[cr]=1;
    for(int i=hd[cr],v;i;i=nxt[i])
      if(ins[v=to[i]]){flag=1;return;}
      else if(!vis[v])dfs(v);
    ins[cr]=0;
  }
  void solve()
  {
    n=strlen(s+1);
    for(int i=1;i<=na;i++)
      a[i].l=rdn(), a[i].r=rdn();
    nb=rdn();
    for(int i=1;i<=nb;i++)
      b[i].l=rdn(), b[i].r=rdn();
    init();
    get_sa(n,26); get_ht(n);
    if(na==1){solve2();return;}

    for(int i=1;i<=nb;i++)fw[i]=cz(b[i].l,b[i].r-b[i].l+1);
    int m=rdn(),u,v;
    while(m--)
      {
    u=rdn(); v=rdn(); vt[u].pb(fw[v]);
      }
    for(int i=1;i<=na;i++)sol(i);
    for(int i=1;i<=na;i++)
      if(!vis[i]){dfs(i);if(flag)break;}
    if(flag){puts("-1");return;}

    for(int i=1;i<=na;i++)
      if(!rd[i])dis[i]=a[i].r-a[i].l+1, q.push(i);
    ll ans=0;
    while(q.size())
      {
    int k=q.front(); q.pop();
    ans=Mx(ans,dis[k]);
    for(int i=hd[k],v;i;i=nxt[i])
      {
        dis[v=to[i]]=Mx(dis[v],dis[k]+w[i]);
        rd[v]--; if(!rd[v])q.push(v);
      }
      }
    printf("%lld\n",ans);
  }
}
int main()
{
  freopen("string.in","r",stdin);
  freopen("string.out","w",stdout);
  int T=rdn();
  while(T--)
    {
      scanf("%s",s+1);
      na=rdn(); if(na<=1000)S1::solve();
    }
  return 0;
}

发现自己很多细节都写错了。

1. vis[ ] 有用在整个字符串范围上,所以大小应该是 N 而不是 M (倒是那个 rd[ ] ,大小是 M 即可)。并且配套的,在 init( ) 的时候要 1~n 的 vis[ ]=0 而不是 1~na 的 vis[ ]=0 ;

2.拓扑找开头的时候顺便赋初值,不是只有开头才赋初值,而是每个点都要 dis[ ] = r-l+1 ,因为自己的 init( ) 里没有管 dis ;

改了这两处就能有 10 分了。

3. log 的大小,即 K 的大小,不是 log 1000 ,而是 log 2e5 ,所以 K 不是 15 而是 20 ;

4.b[ ] 以及相关的 fw[ ] , sta[ ] 的大小不是 M 而是 N ;

5.在 na==1 的特判里,有一个 qry_ht( cr , b[ i ].l ) ,那里应该是 qry_ht( cr , rk[ b[ i ].l ] ) 。

改掉这些就能得到预计的 40 分啦……

错误主要是:数组大小、初值处理、手误。在写代码的时候应该更用心。

现在的代码交到洛谷上,只能过第 4 个点;但本地测的是 40 分。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
#define pb push_back
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
ll Mx(ll a,ll b){return a>b?a:b;}
ll Mn(ll a,ll b){return a<b?a:b;}
const int N=2e5+5;
char s[N]; int na,nb;
namespace S1{
  const int M=1005,K=20,M2=M*M;//K=20 not 15
  int n,sa[N],rk[N],tp[N],tx[30],ht[N][K],lg[N],bin[K];
  int hd[M],xnt,to[M2],nxt[M2],w[M2]; ll dis[M];
  int rd[M]; bool vis[N],ins[M],flag;//rd[M]not[N]//vis[N]not[M]
  struct Node{
    int l,r;
    bool operator< (const Node &b)const
    {return r==b.r?l>b.l:r<b.r;}
  }a[M],b[N],fw[N],sta[N];//[N] not [M]//!!!
  vector<Node> vt[M];
  queue<int> q;
  void init()
  {
    xnt=0;for(int i=1;i<=na;i++)hd[i]=rd[i]=0;
    flag=0;for(int i=1;i<=na;i++)ins[i]=0;
    for(int i=1;i<=n;i++)vis[i]=0;//n not na
    for(int i=1;i<=na;i++)vt[i].clear();//
  }
  void add(int x,int y,int z)
  {to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;w[xnt]=z;rd[y]++;}
  void Rsort(int n,int nm)
  {
    for(int i=1;i<=nm;i++)tx[i]=0;
    for(int i=1;i<=n;i++)tx[rk[i]]++;
    for(int i=2;i<=nm;i++)tx[i]+=tx[i-1];
    for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
  }
  void get_sa(int n,int nm)
  {
    for(int i=1;i<=n;i++)rk[i]=s[i]-'a'+1,tp[i]=i;
    Rsort(n,nm);
    for(int k=1;k<=n;k<<=1)
      {
    int tot=0;
    for(int i=n-k+1;i<=n;i++)tp[++tot]=i;
    for(int i=1;i<=n;i++)
      if(sa[i]>k)tp[++tot]=sa[i]-k;
    Rsort(n,nm);
    for(int i=1;i<=n;i++)tp[i]=rk[i];
    rk[sa[1]]=nm=1;
    for(int i=2;i<=n;i++)
      {
        int u=sa[i]+k,v=sa[i-1]+k; if(u>n)u=0;if(v>n)v=0;
        rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[u]==tp[v])?nm:++nm;
      }
    if(nm==n)break;
      }
  }
  void get_ht(int n)
  {
    for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
    bin[0]=1;
    for(int i=1;i<=lg[n];i++)bin[i]=bin[i-1]<<1;
    for(int i=1,k=0,j;i<=n;i++)//k=0
      {
    for((k?k--:0),j=sa[rk[i]-1];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
    ht[rk[i]][0]=k;
      }
    for(int t=1;t<=lg[n];t++)
      for(int i=1;i+bin[t]-1<=n;i++)
    ht[i][t]=Mn(ht[i][t-1],ht[i+bin[t-1]][t-1]);
  }
  int qry_ht(int l,int r)
  {
    if(l==r)return n-sa[l]+1;
    if(l>r)swap(l,r); l++; int d=lg[r-l+1];
    return Mn(ht[l][d],ht[r-bin[d]+1][d]);
  }
  void solve2()
  {
    int m=rdn();
    while(m--)rdn(), rdn();
    int cr=rk[a[1].l];
    for(int i=1;i<=nb;i++)
      if(qry_ht(cr,rk[b[i].l])>=b[i].r-b[i].l+1)//rk[]!!!!
    {flag=1;break;}
    if(flag)puts("-1"); else printf("%d\n",a[1].r-a[1].l+1);
  }
  Node cz(int p,int len)
  {
    Node ret; p=rk[p];//rk
    int l=1,r=p,ans=p;
    while(l<=r)
      {
    int mid=l+r>>1;
    if(qry_ht(mid,p)>=len)ans=mid,r=mid-1;
    else l=mid+1;
      }
    ret.l=ans;
    l=p; r=n; ans=p;
    while(l<=r)
      {
    int mid=l+r>>1;
    if(qry_ht(mid,p)>=len)ans=mid,l=mid+1;
    else r=mid-1;
      }
    ret.r=ans; return ret;
  }
  void sol(int bh)
  {
    sort(vt[bh].begin(),vt[bh].end());
    int top=0;
    for(int i=0,lm=vt[bh].size();i<lm;i++)
      {
    while(top&&sta[top].l>=vt[bh][i].l)top--;
    if(!top||sta[top].r<vt[bh][i].l)
      { sta[++top]=vt[bh][i];continue;}
    sta[top].r=vt[bh][i].r;
      }
    for(int i=1;i<=top;i++)
      for(int j=sta[i].l;j<=sta[i].r;j++)vis[j]=1;
    for(int i=1;i<=na;i++)
      if(vis[rk[a[i].l]])add(bh,i,a[i].r-a[i].l+1);
    memset(vis,0,sizeof vis);
  }
  void dfs(int cr)
  {
    vis[cr]=1;ins[cr]=1;
    for(int i=hd[cr],v;i;i=nxt[i])
      if(ins[v=to[i]]){flag=1;return;}
      else if(!vis[v])dfs(v);
    ins[cr]=0;
  }
  void solve()
  {
    n=strlen(s+1);
    for(int i=1;i<=na;i++)
      a[i].l=rdn(), a[i].r=rdn();
    nb=rdn();
    for(int i=1;i<=nb;i++)
      b[i].l=rdn(), b[i].r=rdn();
    init();
    get_sa(n,26); get_ht(n);
    if(na==1){solve2();return;}

    for(int i=1;i<=nb;i++)fw[i]=cz(b[i].l,b[i].r-b[i].l+1);
    int m=rdn(),u,v;
    while(m--)
      {
    u=rdn(); v=rdn(); vt[u].pb(fw[v]);
      }
    for(int i=1;i<=na;i++)sol(i);
    for(int i=1;i<=na;i++)
      if(!vis[i]){dfs(i);if(flag)break;}
    if(flag){puts("-1");return;}

    for(int i=1;i<=na;i++)
      //if(!rd[i])dis[i]=a[i].r-a[i].l+1, q.push(i);//not this!!!
      {
    dis[i]=a[i].r-a[i].l+1;
    if(!rd[i])q.push(i);
      }
    ll ans=0;
    while(q.size())
      {
    int k=q.front(); q.pop();
    ans=Mx(ans,dis[k]);
    for(int i=hd[k],v;i;i=nxt[i])
      {
        dis[v=to[i]]=Mx(dis[v],dis[k]+w[i]);
        rd[v]--; if(!rd[v])q.push(v);
      }
      }
    printf("%lld\n",ans);
  }
}
int main()
{
  freopen("string.in","r",stdin);
  freopen("string.out","w",stdout);
  int T=rdn();
  while(T--)
    {
      scanf("%s",s+1);
      na=rdn(); if(na<=1000)S1::solve();
    }
  return 0;
}
View Code

 上面的代码其实还是爆零的……

那个 tx[ ] 的大小应该是 N 而不是字符集大小!!!因为之后 rk[ ] 就会变成 N 。如果不开 O2 ,好像测的没问题,但开 O2 就会爆零了。

80 分的代码就是线段树优化连边。其实没有想象的复杂,不用建两个线段树之类的,因为是有向边。

线段树的父亲向孩子连边,叶子向它要连的区间节点连边。

自己的方法是把 a 排序,二分出 b 在 sa 数组上的控制范围(是对 sa 角标的而非对 a 的范围,不然判断麻烦),再在线段树上一边走一边看范围。注意判断一下如果 l==r 都不合法就要及时 return 。

本地开了 O2 测得 80 。交到洛谷上还是只能过第 4 个点,不知为何。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
#define pb push_back
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
ll Mx(ll a,ll b){return a>b?a:b;}
ll Mn(ll a,ll b){return a<b?a:b;}
const int N=2e5+5,K=20;
char s[N]; int na,nb;
int n,sa[N],rk[N],tp[N],tx[N],ht[N][K],lg[N],bin[K];//tx[N] not [30]!!!
struct Node{
  int l,r,c,id;
  bool operator< (const Node &b)const
  {return r==b.r?l>b.l:r<b.r;}
}a[N],b[N];
void Rsort(int n,int nm)
{
  for(int i=1;i<=nm;i++)tx[i]=0;
  for(int i=1;i<=n;i++)tx[rk[i]]++;
  for(int i=2;i<=nm;i++)tx[i]+=tx[i-1];
  for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
}
void get_sa(int n,int nm)
{
  int mx=0,mn=N;
  for(int i=1;i<=n;i++)
    {
      rk[i]=s[i]-'a'+1,tp[i]=i;
      mx=Mx(mx,rk[i]); mn=Mn(mn,rk[i]);
    }
  Rsort(n,nm);
  for(int k=1;k<=n;k<<=1)
    {
      int tot=0;
      for(int i=n-k+1;i<=n;i++)tp[++tot]=i;
      for(int i=1;i<=n;i++)
    if(sa[i]>k)tp[++tot]=sa[i]-k;
      Rsort(n,nm);
      for(int i=1;i<=n;i++)tp[i]=rk[i];
      rk[sa[1]]=nm=1;
      for(int i=2;i<=n;i++)
    {
      int u=sa[i]+k,v=sa[i-1]+k; if(u>n)u=0;if(v>n)v=0;
      rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[u]==tp[v])?nm:++nm;
    }
      if(nm==n)break;
    }
}
void get_ht(int n)
{
  for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
  bin[0]=1;
  for(int i=1;i<=lg[n];i++)bin[i]=bin[i-1]<<1;
  for(int i=1,k=0,j;i<=n;i++)//k=0
    {
      for((k?k--:0),j=sa[rk[i]-1];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
      ht[rk[i]][0]=k;
    }
  for(int t=1;t<=lg[n];t++)
    for(int i=1;i+bin[t]-1<=n;i++)
      ht[i][t]=Mn(ht[i][t-1],ht[i+bin[t-1]][t-1]);
}
int qry_ht(int l,int r)
{
  if(l==r)return n-sa[l]+1;
  if(l>r)swap(l,r); l++; int d=lg[r-l+1];
  return Mn(ht[l][d],ht[r-bin[d]+1][d]);
}
Node cz(int p,int len)
{
  Node ret; p=rk[p];//rk
  int l=1,r=p,ans=p;
  while(l<=r)
    {
      int mid=l+r>>1;
      if(qry_ht(mid,p)>=len)ans=mid,r=mid-1;
      else l=mid+1;
    }
  ret.l=ans;
  l=p; r=n; ans=p;
  while(l<=r)
    {
      int mid=l+r>>1;
      if(qry_ht(mid,p)>=len)ans=mid,l=mid+1;
      else r=mid-1;
    }
  ret.r=ans; return ret;
}
namespace S2{
  const int M=N<<1,M2=7600005;
  int tot,Ls[M],Rs[M],c[M],ps[N];
  int hd[M],xnt,to[M2],nxt[M2],rd[M];
  ll dis[M]; bool vis[M],ins[M],flag;
  vector<int> vt[N];
  queue<int> q;
  bool cmp(Node u,Node v){return rk[u.l]<rk[v.l];}
  void add(int x,int y)
  { to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;rd[y]++;}
  void init()
  {
    xnt=0;for(int i=1;i<=tot;i++)hd[i]=rd[i]=0;
    flag=0;for(int i=1;i<=tot;i++)vis[i]=ins[i]=0;
    for(int i=1;i<=nb;i++)vt[i].clear();//
  }
  void build(int l,int r,int cr)
  {
    c[cr]=0;
    if(l==r){ps[a[l].id]=cr;c[cr]=a[l].c;return;}
    int mid=l+r>>1;
    ls=++tot; add(cr,ls); build(l,mid,ls);
    rs=++tot; add(cr,rs); build(mid+1,r,rs);
  }
  void qry(int l,int r,int cr,int L,int R,int k)
  {
    if(rk[a[l].l]>=L&&rk[a[r].l]<=R)//
      {vt[k].pb(cr);return;}
    if(l==r)return; int mid=l+r>>1;//return
    if(L<=rk[a[mid].l])qry(l,mid,ls,L,R,k);
    if(rk[a[mid+1].l]<=R)qry(mid+1,r,rs,L,R,k);
  }
  void dfs(int cr)
  {
    vis[cr]=ins[cr]=1;
    for(int i=hd[cr],v;i;i=nxt[i])
      if(ins[v=to[i]]){flag=1;return;}
      else if(!vis[v]){dfs(v);if(flag)return;}
    ins[cr]=0;
  }
  void solve()
  {
    init();
    for(int i=1;i<=na;i++)a[i].id=i;
    sort(a+1,a+na+1,cmp); tot=1; build(1,na,1);
    for(int i=1;i<=nb;i++)
      {
    Node d=cz(b[i].l,b[i].c);
    qry(1,na,1,d.l,d.r,i);
      }
    int m=rdn(),u,v;
    while(m--)
      {
    u=rdn();v=rdn();
    for(int i=0,lm=vt[v].size();i<lm;i++)
      add(ps[u],vt[v][i]);
      }
    for(int i=1;i<=tot;i++)
      if(!vis[i]){dfs(i);if(flag)break;}
    if(flag){puts("-1");return;}

    for(int i=1;i<=tot;i++)
      { dis[i]=c[i]; if(!rd[i])q.push(i);}
    ll ans=0;
    while(q.size())
      {
    int k=q.front(); q.pop();
    ans=Mx(ans,dis[k]);
    for(int i=hd[k],v;i;i=nxt[i])
      {
        dis[v=to[i]]=Mx(dis[v],dis[k]+c[v]);
        if((--rd[v])==0)q.push(v);
      }
      }
    printf("%lld\n",ans);
  }
}
int main()
{
  freopen("string.in","r",stdin);
  freopen("string.out","w",stdout);
  int T=rdn();
  while(T--)
    {
      scanf("%s",s+1); n=strlen(s+1);
      na=rdn(); int mn=n;
      for(int i=1;i<=na;i++)
    {
      a[i].l=rdn(); a[i].r=rdn(); a[i].c=a[i].r-a[i].l+1;
      mn=Mn(mn,a[i].c);
    }
      nb=rdn(); int mx=0;
      for(int i=1;i<=nb;i++)
    {
      b[i].l=rdn(); b[i].r=rdn(); b[i].c=b[i].r-b[i].l+1;
      mx=Mx(mx,b[i].c);
    }
      get_sa(n,26); get_ht(n);
      if(mx<=mn)S2::solve();
    }
  return 0;
}
View Code

如果 |a|<|b| ,那么 b 在 sa 上对应的那个区间里不是所有的 a 都可以连边。

但如果把 a 按真实的字典序排序,那么 b 对应的 a 仍然是一段连续的区间。

按真实的字典序排序也很好做,只要作出后缀数组,然后查一下 LCP 看是不是大于两个串长度的较小值就行。(如果小于,就看不同字符;不然看长度谁短)

一个 b 可以在排序后的 a 上二分得到区间。合法区间需要满足 a[ ] >= b && LCP( a[ ] , b ) == b.len ;如果 a[ ] < b 就向右,如果 a[ ] >= b && LCP( a[ ] , b ) < b.len 就向左,这样就可以二分啦。

本地可过,交到洛谷上还是只有第 4 个点不 RE 。真是令人气急败坏!不管了。

交到 LOJ 上会除了第 4 个点之外全 WA 。但选择 C++(NOI) 提交的话就可过。不知为何。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define ll long long
#define pb push_back
#define ls Ls[cr]
#define rs Rs[cr]
using namespace std;
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
ll Mx(ll a,ll b){return a>b?a:b;}
ll Mn(ll a,ll b){return a<b?a:b;}
const int N=2e5+5,K=20,M=N<<1,M2=7600005;
char s[N]; int na,nb;
int n,sa[N],rk[N],tp[N],tx[N],ht[N][K],lg[N],bin[K];//tx[N] not [30]!!!
int tot,Ls[M],Rs[M],c[M],ps[N];
int hd[M],xnt,to[M2],nxt[M2],rd[M];
ll dis[M]; bool vis[M],ins[M],flag;
vector<int> vt[N];
queue<int> q;
void Rsort(int n,int nm)
{
  for(int i=1;i<=nm;i++)tx[i]=0;
  for(int i=1;i<=n;i++)tx[rk[i]]++;
  for(int i=2;i<=nm;i++)tx[i]+=tx[i-1];
  for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
}
void get_sa(int n,int nm)
{
  int mx=0,mn=N;
  for(int i=1;i<=n;i++)
    {
      rk[i]=s[i]-'a'+1,tp[i]=i;
      mx=Mx(mx,rk[i]); mn=Mn(mn,rk[i]);
    }
  Rsort(n,nm);
  for(int k=1;k<=n;k<<=1)
    {
      int tot=0;
      for(int i=n-k+1;i<=n;i++)tp[++tot]=i;
      for(int i=1;i<=n;i++)
    if(sa[i]>k)tp[++tot]=sa[i]-k;
      Rsort(n,nm);
      for(int i=1;i<=n;i++)tp[i]=rk[i];
      rk[sa[1]]=nm=1;
      for(int i=2;i<=n;i++)
    {
      int u=sa[i]+k,v=sa[i-1]+k; if(u>n)u=0;if(v>n)v=0;
      rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[u]==tp[v])?nm:++nm;
    }
      if(nm==n)break;
    }
}
void get_ht(int n)
{
  for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
  bin[0]=1;
  for(int i=1;i<=lg[n];i++)bin[i]=bin[i-1]<<1;
  for(int i=1,k=0,j;i<=n;i++)//k=0
    {
      for((k?k--:0),j=sa[rk[i]-1];i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
      ht[rk[i]][0]=k;
    }
  for(int t=1;t<=lg[n];t++)
    for(int i=1;i+bin[t]-1<=n;i++)
      ht[i][t]=Mn(ht[i][t-1],ht[i+bin[t-1]][t-1]);
}
int qry_ht(int l,int r)
{
  if(l==r)return n-sa[l]+1;
  if(l>r)swap(l,r); l++; int d=lg[r-l+1];
  return Mn(ht[l][d],ht[r-bin[d]+1][d]);
}
struct Node{
  int l,r,c,id;
  Node(int l=0,int r=0):l(l),r(r) {c=id=0;}
  bool operator< (const Node &b)const
  {
    int d=qry_ht(rk[l],rk[b.l]), len=Mn(c,b.c);
    if(d<len)return s[l+d]<s[b.l+d];
    else return c<b.c;
  }
}a[N],b[N];
void add(int x,int y)
{ to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;rd[y]++;}
void init()
{
  xnt=0;for(int i=1;i<=tot;i++)hd[i]=rd[i]=0;
  flag=0;for(int i=1;i<=tot;i++)vis[i]=ins[i]=0;
  for(int i=1;i<=nb;i++)vt[i].clear();//
}
Node cz(Node cr)
{
  Node ret;
  int l=1,r=na,ans=0, st=rk[cr.l],lm=cr.c;
  while(l<=r)
    {
      int mid=l+r>>1;
      if(a[mid]<cr)l=mid+1;
      else if(qry_ht(st,rk[a[mid].l])<lm)r=mid-1;
      else ans=mid,r=mid-1;
    }
  if(!ans)return Node(0,0);
  ret.l=ans;
  l=1; r=na; ans=0;
  while(l<=r)
    {
      int mid=l+r>>1;
      if(a[mid]<cr)l=mid+1;
      else if(qry_ht(st,rk[a[mid].l])<lm)r=mid-1;
      else ans=mid,l=mid+1;
    }
  ret.r=ans; return ret;
}
void build(int l,int r,int cr)
{
  c[cr]=0;
  if(l==r){ps[a[l].id]=cr;c[cr]=a[l].c;return;}
  int mid=l+r>>1;
  ls=++tot; add(cr,ls); build(l,mid,ls);
  rs=++tot; add(cr,rs); build(mid+1,r,rs);
}
void qry(int l,int r,int cr,int L,int R,int k)
{
  if(l>=L&&r<=R){vt[k].pb(cr);return;}
  if(l==r)return; int mid=l+r>>1;//return
  if(L<=mid)qry(l,mid,ls,L,R,k);
  if(mid<R)qry(mid+1,r,rs,L,R,k);
}
void dfs(int cr)
{
  vis[cr]=ins[cr]=1;
  for(int i=hd[cr],v;i;i=nxt[i])
    if(ins[v=to[i]]){flag=1;return;}
    else if(!vis[v]){dfs(v);if(flag)return;}
  ins[cr]=0;
}
void solve()
{
  init();
  for(int i=1;i<=na;i++)a[i].id=i;
  sort(a+1,a+na+1); tot=1; build(1,na,1);
  for(int i=1;i<=nb;i++)
    {
      Node d=cz(b[i]);
      qry(1,na,1,d.l,d.r,i);
    }
  int m=rdn(),u,v;
  while(m--)
    {
      u=rdn();v=rdn();
      for(int i=0,lm=vt[v].size();i<lm;i++)
    add(ps[u],vt[v][i]);
    }
  for(int i=1;i<=tot;i++)
    if(!vis[i]){dfs(i);if(flag)break;}
  if(flag){puts("-1");return;}

  for(int i=1;i<=tot;i++)
    { dis[i]=c[i]; if(!rd[i])q.push(i);}
  ll ans=0;
  while(q.size())
    {
      int k=q.front(); q.pop();
      ans=Mx(ans,dis[k]);
      for(int i=hd[k],v;i;i=nxt[i])
    {
      dis[v=to[i]]=Mx(dis[v],dis[k]+c[v]);
      if((--rd[v])==0)q.push(v);
    }
    }
  printf("%lld\n",ans);
}
int main()
{
  freopen("string.in","r",stdin);
  freopen("string.out","w",stdout);
  int T=rdn();
  while(T--)
    {
      scanf("%s",s+1); n=strlen(s+1);
      na=rdn();
      for(int i=1;i<=na;i++)
    {
      a[i].l=rdn(); a[i].r=rdn(); a[i].c=a[i].r-a[i].l+1;
    }
      nb=rdn();
      for(int i=1;i<=nb;i++)
    {
      b[i].l=rdn(); b[i].r=rdn(); b[i].c=b[i].r-b[i].l+1;
    }
      get_sa(n,26); get_ht(n);
      solve();
    }
  return 0;
}
View Code

 

posted on 2019-04-08 17:27  Narh  阅读(260)  评论(0编辑  收藏  举报

导航