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


posted @ 2018-03-27 19:22  Duan2baka  阅读(158)  评论(0编辑  收藏  举报