[SCOI2012]喵星球上的点名

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;
}

posted @ 2021-04-01 10:31  Troverld  阅读(50)  评论(0编辑  收藏  举报