BZOJ[2780][Spoj]8093 Sevenk Love Oimaster 后缀数组
此题精神AC
SAM水题,但是我不会SAM
将所有串串在一起,对这个大串求SA
对于每一个模式串,能匹配的都是在rk意义上连续的一段
二分出这一段的左右端点
现在要做的就是统计这段区间有多少不同的颜色
然后就同呵呵的项链
我就是要用莫队来做(UPD 发blog10min以后:BIT也过不了)
本机300ms,校OJ 700msA了
能用的卡常技巧我都用了
这篇博客留着等以后卡常的时候参考
代码如下:
莫队
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<cstdio>
#include<cmath>
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#define N 600050
using namespace std;
inline char nc(){
static char buf[1000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
register int x=0,f=1;char c;
do c=nc(),f=c=='-'?-1:f; while(!isdigit(c));
do x=(x<<3)+(x<<1)+c-'0',c=nc(); while(isdigit(c));
return x*f;
}
int n,m,top,t,tot,len,l,r,mid,Block_Size,tmp,top1;
typedef int iarr[N];
iarr a,SA,rk,buck,las,height,ans,L,R,pw,block,num,s1;
int f[N][25];
char s[N];
inline int Max(int a,int b){return a>b?a:b;}
inline int Min(int a,int b){return a<b?a:b;}
inline bool judge(int x,int y,int k){
return las[x]==las[y] && las[x+k]==las[y+k];
}
inline void Radix_Sort(){
for(register int i=1;i<=m;++i) buck[i]=0;
for(register int i=1;i<=n;++i) buck[rk[las[i]]]++;
for(register int i=2;i<=m;++i) buck[i]+=buck[i-1];
for(register int i=n;i>=1;--i) SA[buck[rk[las[i]]]--]=las[i];
top=m=0;
}
inline void Get_SA(){
for(register int i=1;i<=n;++i){
rk[i]=s[i];las[i]=i;
}
m=127;Radix_Sort();
for(register int i=1;m^n;i<<=1){
for(register int j=n-i+1;j<=n;++j) las[++top]=j;
for(register int j=1;j<=n;++j) if(SA[j]>i) las[++top]=SA[j]-i;
Radix_Sort();
for(register int j=1;j<=n;++j) las[j]=rk[j];
for(register int j=1;j<=n;++j) rk[SA[j]]=judge(SA[j-1],SA[j],i)?m:++m;
}
for(register int i=1,j=0;i<=n;++i,j=j?j-1:0){
while(s[i+j]==s[SA[rk[i]-1]+j]) ++j;
height[rk[i]]=j;
}
}
inline void Get_ST(){
pw[0]=1;
for(register int i=1;pw[i-1]<=n;++i) pw[i]=1<<i;
for(register int i=1;i<=n;++i) f[i][0]=height[i];
for(register int j=1;pw[j]<=n;++j)
for(register int i=1;i+pw[j-1]<=n;++i)
f[i][j]=Min(f[i+pw[j-1]][j-1],f[i][j-1]);
}
inline int LCP(int x,int y){
if(x>y) swap(x,y);
int t=log2(y-x+1);
return Min(f[x][t],f[y-pw[t]+1][t]);
}
struct Query{
int l,r,id;
}q[N];
inline bool cmp(Query a,Query b){
return block[a.l]==block[b.l]?a.r<b.r:block[a.l]<block[b.l];
}
inline void Update(int x,int k){
if(!~x) return;
if(!num[x]) ++tmp;
num[x]+=k;
if(!num[x]) --tmp;
}
int main(){
memset(a,-1,sizeof a);
n=read();tot=read();
for(register int i=1;i<=n;i++){
do s[++top]=nc(),a[top]=i; while(isalpha(s[top]));
s[top]=126;
}
for(register int i=1;i<=tot;i++){
L[i]=top+1;
do s[++top]=nc(); while(isalpha(s[top]));
R[i]=top-1;
s[top]=126;
}
n=top;
Get_SA();Get_ST();
Block_Size=sqrt(tot);
for(register int i=1;i<=tot;i++){
block[i]=(i-1)/Block_Size+1;
len=R[i]-L[i]+1;
L[i]=rk[L[i]];
l=1;r=L[i]-1;
if(height[L[i]]<len) q[i].l=L[i];
else while(l<=r){
mid=l+r>>1;
if(LCP(mid+1,L[i])>=len)
q[i].l=mid,r=mid-1;
else l=mid+1;
}
l=L[i]+1;r=n;
if(height[L[i]+1]<len) q[i].r=L[i];
else while(l<=r){
mid=l+r>>1;
if(LCP(L[i]+1,mid)>=len)
q[i].r=mid,l=mid+1;
else r=mid-1;
}
q[i].id=i;
}
sort(q+1,q+tot+1,cmp);
l=1;r=0;
for(register int i=1;i<=tot;i++){
while(l<q[i].l) Update(a[SA[l++]],-1);
while(l>q[i].l) Update(a[SA[--l]],1);
while(r<q[i].r) Update(a[SA[++r]],1);
while(r>q[i].r) Update(a[SA[r--]],-1);
ans[q[i].id]=tmp;
}
for(register int i=1;i<=tot;i++){
printf("%d\n",ans[i]);
}
return 0;
}
BIT
#include<algorithm>
#include<cstdio>
#pragma GCC optimize(3)
#define isdigit(c) (c>='0' && c<='9')
#define isalpha(c) (c>='a' && c<='z')
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,N,stdin),p1==p2)?EOF:*p1++)
#define judge(a,b,c) (las[a]==las[b] && las[a+c]==las[b+c])
#define Swap(a,b) (a=a^b,b=a^b,a=a^b)
#define Min(a,b) (a<b?a:b)
#define Add(a,b) for(;a<=n;a=a+(a&-a)) g[a]+=b;
#define Update(x,k) if(x){\
if(!num[x]) ++tmp;\
num[x]=num[x]+k;\
if(!num[x]) --tmp;}
#define N 600050
using namespace std;
char buf[N],*p1=buf,*p2=buf;
int xx,ff;
char c;
inline int read(){
xx=0;ff=1;
do c=nc(),ff=c=='-'?-1:ff; while(!isdigit(c));
do xx=(xx<<3)+(xx<<1)+c-'0',c=nc(); while(isdigit(c));
return xx*ff;
}
int n,m,top,t,len,tmp,top1;
int a[N],SA[N],rk[N],buck[N],las[N],height[N],ans[N],L[N],R[N],pw[N],num[N],g[N],nex[N],b[N],log2[N],s1[31];
int f[25][N];
char s[N];
inline void Radix_Sort(){
register int i;
for(i=1;i<=m;++i) buck[i]=0;
for(i=1;i<=n;++i) buck[rk[las[i]]]++;
for(i=2;i<=m;++i) buck[i]+=buck[i-1];
for(i=n;i>=1;--i) SA[buck[rk[las[i]]]--]=las[i];
top=m=0;
}
inline void Get_SA(){
register int i,j;
for(i=1;i<=n;++i){
rk[i]=s[i];las[i]=i;
}
m=127;Radix_Sort();
for(i=1;m^n;i<<=1){
for(j=n-i+1;j<=n;++j) las[++top]=j;
for(j=1;j<=n;++j) if(SA[j]>i) las[++top]=SA[j]-i;
Radix_Sort();
for(j=1;j<=n;++j) las[j]=rk[j];
for(j=1;j<=n;++j) rk[SA[j]]=judge(SA[j-1],SA[j],i)?m:++m;
}
for(i=1,j=0;i<=n;++i,j=j?j-1:0){
while(s[i+j]==s[SA[rk[i]-1]+j]) ++j;
height[rk[i]]=j;
}
}
inline void Get_ST(){
pw[0]=1;
register int i,j;
for(i=1;pw[i-1]<=n;++i){
pw[i]=1<<i;
for(j=pw[i-1]+1;j<=pw[i];j++) log2[j]=i-1;
}
for(i=1;i<=n;++i) f[0][i]=height[i];
for(j=1;pw[j]<=n;++j)
for(i=1;i+pw[j-1]<=n;++i)
f[j][i]=Min(f[j-1][i+pw[j-1]],f[j-1][i]);
}
inline int LCP(register int x,register int y){
if(x>y) Swap(x,y);
register int t=log2[y-x+1];
return Min(f[t][x],f[t][y-pw[t]+1]);
}
struct Query{
int l,r,id;
}q[N];
inline char cmp(register Query a,register Query b){
return a.l<b.l;
}
inline int Sum(register int x){
register int tmp=0;
for(;x;x=x-(x&-x))
tmp=tmp+g[x];
return tmp;
}
inline void write(int x){
top1=0;
while(x){
s1[++top1]=x%10;
x=x/10;
}
for(register int i=top1;i;i--) putchar(s1[i]+'0');putchar('\n');
}
main(){
freopen("aa1.in","r",stdin);
freopen("u.out","w",stdout);
register int i,j,l,r,mid,maxx,tot;
maxx=n=read();tot=read();
for(i=1;i<=n;i+=2){
do s[++top]=nc(),a[top]=i; while(isalpha(s[top]));
s[top]=126;
if(i+1>n) break;
do s[++top]=nc(),a[top]=i+1; while(isalpha(s[top]));
s[top]=126;
}
for(i=1;i<=tot;i+=2){
L[i]=top+1;
do s[++top]=nc(); while(isalpha(s[top]));
R[i]=top-1;
s[top]=126;
if(i+1>tot) break;
L[i+1]=top+1;
do s[++top]=nc(); while(isalpha(s[top]));
R[i+1]=top-1;
s[top]=126;
}
n=top;
Get_SA();Get_ST();
for(i=1;i<=tot;++i){
len=R[i]-L[i]+1;
L[i]=rk[L[i]];
l=1;r=L[i]-1;
if(height[L[i]]<len) q[i].l=L[i];
else while(l<=r){
mid=l+r>>1;
if(LCP(mid+1,L[i])>=len)
q[i].l=mid,r=mid-1;
else l=mid+1;
}
l=L[i]+1;r=n;
if(height[L[i]+1]<len) q[i].r=L[i];
else while(l<=r){
mid=l+r>>1;
if(LCP(L[i]+1,mid)>=len)
q[i].r=mid,l=mid+1;
else r=mid-1;
}
q[i].id=i;
}
sort(q+1,q+tot+1,cmp);
for(i=n;i>=1;i-=2){
if(a[SA[i]]) nex[i]=b[a[SA[i]]],b[a[SA[i]]]=i;
if(i-1>=1 && a[SA[i-1]]) nex[i-1]=b[a[SA[i-1]]],b[a[SA[i-1]]]=i-1;
}
for(i=1;i<=maxx;i+=2){
if(b[i]) Add(b[i],1);
if(i+1<=maxx && b[i+1]) Add(b[i+1],1);
}
l=1;
for(i=1;i<=tot;i+=2){
while(l<q[i].l){
if(nex[l]) Add(nex[l],1);
++l;
}
ans[q[i].id]=Sum(q[i].r)-Sum(q[i].l-1);
if(i+1>tot){
break;
}
while(l<q[i+1].l){
if(nex[l]) Add(nex[l],1);
++l;
}
ans[q[i+1].id]=Sum(q[i+1].r)-Sum(q[i+1].l-1);
}
for(i=1;i<=tot;i+=2){
write(ans[i]);
if(i+1<=tot) write(ans[i+1]);
}
return 0;
}