WIKIOI P2403题解

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define lowbit(x)((-x)&x)
#define MAXN 20010
#define MAXM 50010
#define MAXL 500010
#define inf 0x7fffffff
#define MAXD 21
int s[MAXL],name[MAXL];
int n,m,lenn[MAXN],lenm[MAXM],firn[MAXN],firm[MAXM],N=0;
int getstring() {
   int len;
   scanf("%d",&len);
   for (int i=0;i++<len;) scanf("%d",&name[i]);
   return len;
}
int sa[MAXL],rank[MAXL],r[MAXL],w[MAXL],x[MAXL],y[MAXL],height[MAXL],b,Nn;
struct saver {
   int v,t;
} c[MAXL];
bool cmp(saver x,saver y) {
   return x.v<y.v;
}
void Make_sa() {
   for (int i=0;i++<N;) c[i].v=s[i],c[i].t=i;
   sort(c+1,c+N+1,cmp);
   Nn=0;
   for (int i=0;i++<N;) {
       if (i==1||c[i].v!=c[i-1].v) Nn++;
       rank[c[i].t]=Nn;
   }
   b=1;
   x[sa[0]=0]=y[0]=-1;
   do {
       for (int i=0;i++<N;) x[i]=rank[i],y[i]=i+b<=N?rank[i+b]:0;
       b<<=1;
       for (int i=0;i<=N;i++) w[i]=0;
       for (int i=0;i++<N;) w[y[i]]++;
       for (int i=0;i++<N;) w[i]+=w[i-1];
       for (int i=0;i++<N;) r[w[y[i]]--]=i;
       for (int i=0;i<=N;i++) w[i]=0;
       for (int i=0;i++<N;) w[x[r[i]]]++;
       for (int i=0;i++<N;) w[i]+=w[i-1];
       for (int i=N;i;i--) sa[w[x[r[i]]]--]=r[i];
       Nn=0;
       for (int i=0;i++<N;) {
           if (x[sa[i]]!=x[sa[i-1]]||y[sa[i]]!=y[sa[i-1]]) Nn++;
           rank[sa[i]]=Nn;
       }
   } while (Nn<N);
   int k=0;
   for (int i=0;i++<N;) {
       k=max(k-1,0);
       height[rank[i]]=k;
       for (int j=k;i+j<=N&&sa[rank[i]-1]+j<=N&&s[i+j]==s[sa[rank[i]-1]+j];j++) height[rank[i]]++;
       k=height[rank[i]];
   }
}
int st[MAXL][MAXD];
void Init_st() {
   for (int i=0;i++<N;) st[i][0]=height[i];
   int d=int(log2(N))+1;
   for (int i=0;i++<d;) {
       for (int j=0;j++<N;) {
           st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
       }
   }
}
int Min(int l,int r) {
   int k=int(log2(r-l+1));
   return min(st[l][k],st[r-(1<<k)+1][k]);
}
int ansn[MAXN],ansm[MAXM],left[MAXM],right[MAXM];
struct node {
   node *next;
   int l,r,t;
   bool flag;
} *head[MAXL];
void Insert(int w,int l,int r,int t,bool flag) {
   node *p=new(node);
   p->next=head[w],p->l=l,p->r=r,p->t=t,p->flag=flag;
   head[w]=p;
}
int next[MAXL],last[MAXL];
bool Cmp(int x,int y) {
   return x<y;
}
struct Bit{
   int t[MAXL],n;
   void Init(int _n) {
       memset(t,0,sizeof(t));
       n=_n;
   }
   void Add(int x,int y) {
       for (;x<=n;x+=lowbit(x)) t[x]+=y;
   }
   int Sum(int x) {
       int rec=0;
       for (;x;x-=lowbit(x)) rec+=t[x];
       return rec;

   }
} bit;
void Solve0() {
   memset(head,0,sizeof(head));
   for (int i=0;i++<m;) Insert(left[i],left[i],right[i],i,true);
   memset(next,0,sizeof(next));
   memset(last,0,sizeof(last));
   memset(w,0,sizeof(w));
   bit.Init(N);
   for (int i=0;i++<n;) {
       for (int j=0;j<lenn[i];j++) r[j]=rank[firn[i]+j];
       sort(r,r+lenn[i],Cmp);
       bit.Add(r[0],1);
       for (int j=0;j<lenn[i]-1;j++) next[r[j]]=r[j+1];
       for (int j=1;j<lenn[i];j++) last[r[j]]=r[j-1];
       for (int j=0;j<lenn[i];j++) w[r[j]]=i;
   }
   for (int i=0;i++<N;) {
       for (node *p=head[i];p;p=p->next) ansm[p->t]=bit.Sum(p->r);
       if (w[i]) bit.Add(i,-1);
       if (next[i]) bit.Add(next[i],1);
   }
}
void Solve1() {
   memset(head,0,sizeof(head));
   memset(ansn,0,sizeof(ansn));
   for (int i=0;i++<m;) Insert(left[i],left[i],right[i],i,true),Insert(right[i]+1,left[i],right[i],i,false);
   bit.Init(N);
   for (int i=0;i<=N;i++) {
       for (node *p=head[i];p;p=p->next) if (p->flag) bit.Add(p->l,1); else bit.Add(p->l,-1);
       ansn[w[i]]+=bit.Sum(i)-bit.Sum(last[i]);
   }
}
void Solve() {
   Init_st();
   for (int i=0;i++<m;) {
       if (height[rank[firm[i]]]<lenm[i]) left[i]=rank[firm[i]]
           ;  else {
               int le=1,ri=rank[firm[i]];
               while (ri-le>1) {
                   int mid=(le+ri)>>1;
                   if (Min(mid,rank[firm[i]])>=lenm[i]) ri=mid
                       ;  else le=mid;
               }
               left[i]=le;
           }
       if (height[rank[firm[i]]+1]<lenm[i]) right[i]=rank[firm[i]]
           ;  else if (Min(rank[firm[i]]+1,N)>=lenm[i]) right[i]=N
               ;  else {
                   int le=rank[firm[i]]+1,ri=N
                   while (ri-le>1) {
                       int mid=(le+ri)>>1;
                       if (Min(rank[firm[i]]+1,mid)>=lenm[i]) le=mid
                           ;  else ri=mid;
                   }
                   right[i]=le;
               }
   }
   Solve0();
   Solve1();
}
int main() {
   s[0]=inf-1;
   scanf("%d%d",&n,&m);
   for (int i=0;i++<n;) {
       lenn[i]=getstring(),firn[i]=N+1;
       for (int j=0;j++<lenn[i];) s[++N]=name[j];
       int delta=getstring();
       lenn[i]++,s[++N]=-inf;
       for (int j=0;j++<delta;) s[++N]=name[j];
       s[++N]=-inf;
       lenn[i]+=delta;
   }
   for (int i=0;i++<m;) {
       firm[i]=N+1,lenm[i]=getstring();
       for (int j=0;j++<lenm[i];) s[++N]=name[j];
       s[++N]=-inf;
   }
   Make_sa();
   Solve();
   for (int i=0;i++<m;) printf("%d\n",ansm[i]);
   for (int i=0;i++<n-1;) printf("%d ",ansn[i]);
   printf("%d\n",ansn[n]);
   return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值