X.[SCOI2012]喵星球上的点名
我居然做出了这题……难以置信!
首先,思路很明显是把所有串全怼一起(包括名字和询问串),加上分隔符,然后跑一遍后缀数组。
我们仍然可以用单调栈求出关于每个询问串与它相同的区间。即,如果以询问串为前缀的那个后缀的\(rank\)是\(p\)的话,它的合法区间\([L,R]\)应该满足\(\forall L<i\leq R,ht_i\geq ht_p\)。注意这里是\(\geq\)而非\(>\),因此应该特别注意处理\(=\)的部分。
这里放一下求出全部\([L,R)\)的代码(注意这里数组中的\([L,R)\)实际上是左闭右开的,而我们最终要求的\([L,R]\)是左闭右闭的,所以接下来用的时候\(R\)要减去\(1\)):
for(int i=1;i<n;i++){
while(tp&&ht[stk[tp]]>ht[i])R[stk[tp--]]=i;
if(ht[stk[tp]]==ht[i])L[i]=L[stk[tp]];
else L[i]=stk[tp];
stk[++tp]=i;
}
while(tp)R[stk[tp--]]=n;
求出所有合法的\([L,R]\)后,我们可以考虑那两个询问了。
首先,对于第一问,发现它就是求区间\([L,R]\)内部所有出现过的姓名串的数量。这不就是[SDOI2009]HH的项链吗?树状数组即可。当然你要真想写莫队也没人拦得住你。
然后,关于第二问,它的意义实际上是将区间\([L,R]\)内部所有出现过的姓名串的计数器增加\(1\)。如果关于询问串下手我们没有办法,但是我们可以关于姓名串下手呀!
我们设一个下标\(i\),它所代表的姓名串为代码中的\(id\big[sa[i]\big]\),我们这里设一个\(c_i\)代表它。我们再设它之前上一个出现的该姓名串的下标为\(LAS_i\)(如果之前没有出现任何这个姓名串的下标,\(LAS_i=-1\))。则显然,所有满足\(i\in[L,R]\)且\(LAS_i<L\)的区间\([L,R]\)都可以对\(c_i\)有贡献。这是什么?二维数点问题呀!
于是我们愉快地排个序就能用线段树求出答案。
复杂度\(O(n\log n)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
int S,T,cnt,id[400100],tms[400100],ans[400100],stt[400100],P,Q,len[400100];
//-------------------Suffix Array Below--------------------
int stk[400100],tp,L[400100],R[400100];
namespace Suffix_Array{
int x[400100],y[400100],sa[400100],ht[400100],rk[400100],buc[400100],s[400100],n,m;
bool mat(int a,int b,int k){
if(y[a]!=y[b])return false;
if((a+k<n)^(b+k<n))return false;
if((a+k<n)&&(b+k<n))return y[a+k]==y[b+k];
return true;
}
void SA(){
for(int i=0;i<n;i++)buc[x[i]=s[i]]++;
for(int i=1;i<=m;i++)buc[i]+=buc[i-1];
for(int i=n-1;i>=0;i--)sa[--buc[x[i]]]=i;
for(int k=1;k<n;k<<=1){
int num=0;
for(int i=n-k;i<n;i++)y[num++]=i;
for(int i=0;i<n;i++)if(sa[i]>=k)y[num++]=sa[i]-k;
for(int i=0;i<=m;i++)buc[i]=0;
for(int i=0;i<n;i++)buc[x[y[i]]]++;
for(int i=1;i<=m;i++)buc[i]+=buc[i-1];
for(int i=n-1;i>=0;i--)sa[--buc[x[y[i]]]]=y[i],y[i]=0;
swap(x,y);
x[sa[0]]=num=0;
for(int i=1;i<n;i++)x[sa[i]]=mat(sa[i],sa[i-1],k)?num:++num;
m=num;
}
for(int i=0;i<n;i++)rk[sa[i]]=i;
for(int i=0,k=0;i<n;i++){
if(!rk[i])continue;
if(k)k--;
int j=sa[rk[i]-1];
while(j+k<n&&i+k<n&&s[j+k]==s[i+k])k++;
ht[rk[i]]=k;
}
}
}
using namespace Suffix_Array;
//------------------Suffix Array Above---------------------
int las[400100],LAS[400100];
//------------------Ask the Queries Below------------------
struct Query{
int l,r,id;
Query(int a=0,int b=0,int c=0){l=a,r=b,id=c;}
}q[400100];
bool cmp1(Query &u,Query &v){
return u.r<v.r;
}
int t[400100];
void add(int x,int y){
x++;
while(x<=n)t[x]+=y,x+=x&-x;
}
int sum(int x){
x++;
int ret=0;
while(x)ret+=t[x],x-=x&-x;
return ret;
}
//------------------Ask the Queries Above------------------
//-----------------Calculate the Times Below---------------
pair<int,int>p[400100];
bool cmp(pair<int,int>&u,pair<int,int>&v){//first:place second:last
return u.second>v.second;
}
bool cmp2(Query &u,Query &v){
return u.l>v.l;
}
#define lson x<<1
#define rson x<<1|1
#define mid ((l+r)>>1)
int tag[1600100];
void pushdown(int x){tag[lson]+=tag[x],tag[rson]+=tag[x],tag[x]=0;}
void modify(int x,int l,int r,int L,int R){
if(l>R||r<L)return;
if(L<=l&&r<=R){tag[x]++;return;}
pushdown(x),modify(lson,l,mid,L,R),modify(rson,mid+1,r,L,R);
}
int query(int x,int l,int r,int P){
if(l>P||r<P)return 0;
if(l==r)return tag[x];
pushdown(x);
return query(lson,l,mid,P)+query(rson,mid+1,r,P);
}
#undef lson
#undef rson
#undef mid
//----------------------Calculate the Times Above----------
int main(){
scanf("%d%d",&S,&T),cnt=10000;
for(int i=1;i<=S;i++){
scanf("%d",&m);
for(int j=0;j<m;j++)scanf("%d",&s[n+j]),id[n+j]=i;
n+=m;
s[n++]=++cnt;
scanf("%d",&m);
for(int j=0;j<m;j++)scanf("%d",&s[n+j]),id[n+j]=i;
n+=m;
s[n++]=++cnt;
}
for(int i=1;i<=T;i++){
scanf("%d",&m),stt[i]=n;
len[i]=m;
for(int j=0;j<m;j++)scanf("%d",&s[n+j]),id[n+j]=S+i;
n+=m;
s[n++]=++cnt;
}
m=cnt;
SA();
for(int i=1;i<n;i++){
while(tp&&ht[stk[tp]]>ht[i])R[stk[tp--]]=i;
if(ht[stk[tp]]==ht[i])L[i]=L[stk[tp]];
else L[i]=stk[tp];
stk[++tp]=i;
}
while(tp)R[stk[tp--]]=n;
for(int i=1;i<=T;i++)if(ht[rk[stt[i]]]==len[i])q[++Q]=Query(L[rk[stt[i]]],R[rk[stt[i]]]-1,i);
// for(int i=0;i<n;i++)printf("%2d::S:%5d id:%d rk:%2d sa:%2d ht:%d\n",i,s[i],id[i],rk[i],sa[i],ht[i]);
// for(int i=1;i<=T;i++)printf("%d %d\n",q[i].l,q[i].r);
sort(q+1,q+Q+1,cmp1),memset(las,-1,sizeof(las));
for(int i=1,j=0;i<=Q;i++){
for(;j<=q[i].r;j++){
if(id[sa[j]]>S||!id[sa[j]])continue;
LAS[j]=las[id[sa[j]]],las[id[sa[j]]]=j;
if(LAS[j]!=-1)add(LAS[j],-1);
add(j,1);
p[++P]=make_pair(j,LAS[j]);
}
ans[q[i].id]=sum(q[i].r)-sum(q[i].l-1);
}
for(int i=1;i<=T;i++)printf("%d\n",ans[i]);
sort(q+1,q+Q+1,cmp2),sort(p+1,p+P+1,cmp);
for(int i=1,j=1;i<=P;i++){
while(j<=Q&&p[i].second<q[j].l)modify(1,0,n-1,q[j].l,q[j].r),j++;
tms[id[sa[p[i].first]]]+=query(1,0,n-1,p[i].first);
}
for(int i=1;i<=S;i++)printf("%d ",tms[i]);
return 0;
}