后缀数组+二分+莫队--luoguP2336 [SCOI2012]喵星球上的点名

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sizeof_you/article/details/85270719

(树状数组那么好写我为什么要写莫队 雾)
传送门

后缀数组就不说了···然后对于每一个询问也插入序列,他的答案是一个 l c p l e n lcp\ge len 区间,可以二分出来,然后就变成区间内问不同数字的个数,这就是裸莫队了···

第二个问题的话可以一边莫队一边计算,记录每个数字上一次出现的位置,然后把这一段的和加上

细节好多的···因为后面询问没有用特殊数字隔开wa了好久

还有莫队排序那样写的真的好快的!

代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 500005
#define LL long long
using namespace std;

inline int rd(){
    int x=0,f=1;char c=getchar();
    while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
    while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
    return x*f;
}
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}

int tot,n,m,q,s[N],sa[N],rk[N],tax[N],tp[N],h[N],st[N][25];
int ans[N],a[N],b[N],siz,vis[N],lst[N];

inline void rsort(){
    for(int i=1;i<=m;i++) tax[i]=0;
    for(int i=1;i<=n;i++) tax[rk[i]]++;
    for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
    for(int i=n;i;i--) sa[tax[rk[tp[i]]]--]=tp[i];
}

inline void ssort(){
    for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
    rsort();
    for(int w=1,p=0;w<=n&&p<n;w<<=1,m=p){
        p=0;
        for(int i=n-w+1;i<=n;i++) tp[++p]=i;
        for(int i=1;i<=n;i++)
            if(sa[i]>w) tp[++p]=sa[i]-w;
        rsort(); swap(rk,tp);
        rk[sa[1]]=p=1;
        for(int i=2;i<=n;i++)
            if(tp[sa[i]]==tp[sa[i-1]] && tp[min(n+1,sa[i]+w)]==tp[min(n+1,sa[i-1]+w)])
                rk[sa[i]]=p;
            else rk[sa[i]]=++p;
    }
}

inline void get_h(){
    int j,k=0;
    for(int i=1;i<=n;i++){
        if(k) --k;
        j=sa[rk[i]-1];
        while(s[j+k]==s[i+k]) k++;
        h[rk[i]]=k;
    }
}

inline void prework(){
    for(int i=1;i<=n;i++) st[i][0]=h[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}

inline int lcp(int l,int r){
    if(l>r) swap(l,r); ++l;
    int k=log2(r-l+1);
    return min(st[l][k],st[r-(1<<k)+1][k]);
}

inline int findl(int pos,int len){
    int l=1,r=pos-1,mid,res;
    while(l<=r){
        mid=l+r>>1;
        if(lcp(mid,pos)>=len) res=mid,r=mid-1;
        else l=mid+1;
    } return res;
}

inline int findr(int pos,int len){
    int l=pos+1,r=n,mid,res;
    while(l<=r){
        mid=l+r>>1;
        if(lcp(mid,pos)>=len) l=mid+1,res=mid;
        else r=mid-1;
    } return res;
}

struct Que{
    int l,r,id,pos;
    bool operator <(const Que &x) const{
        if(l/siz!=x.l/siz) return l<x.l;
        if((l/siz)&1) return r<x.r;
        return r>x.r;
    /*	if(l/siz==x.l/siz) return r<x.r;
        return l<x.l;*/
    }
}que[N];
inline bool cmp(Que x,Que y){return x.l<y.l||(x.l==y.l&&x.r<y.r);}

inline void solve(){
    int pos,l,r,cnt=0,len;
    for(int i=1;i<=q;i++){
        pos=rk[que[i].pos],len=que[i+1].pos-que[i].pos-1;
        if(h[pos]<len) l=pos;
        else l=findl(pos,len);
        if(h[pos+1]<len) r=pos;
        else r=findr(pos,len);
        que[i].l=l,que[i].r=r;
    }
    sort(que+1,que+q+1);
    int L=1,R=0;
    for(int i=1;i<=q;i++){
        while(R<que[i].r){R++; if(++vis[b[sa[R]]]==1) cnt++,lst[b[sa[R]]]=i;}
        while(L<que[i].l){if(--vis[b[sa[L]]]==0) cnt--,a[b[sa[L]]]+=i-lst[b[sa[L]]]; L++;}
        while(R>que[i].r){if(--vis[b[sa[R]]]==0) cnt--,a[b[sa[R]]]+=i-lst[b[sa[R]]]; R--;}
        while(L>que[i].l){L--; if(++vis[b[sa[L]]]==1) cnt++,lst[b[sa[L]]]=i;}
        ans[que[i].id]=cnt-(vis[0]!=0);
    }
}

int main(){
    tot=rd(); q=rd(); m=10001;
    for(int i=1;i<=tot;i++){
        int l=rd();
        while(l--) s[++n]=rd(),b[n]=i;
        l=rd(); s[++n]=++m;
        while(l--) s[++n]=rd(),b[n]=i; s[++n]=++m;
    }
    for(int i=1;i<=q;i++) {
        int l=rd(); que[i].pos=n+1; que[i].id=i;
        while(l--) s[++n]=rd(); s[++n]=++m;
    } que[q+1].pos=n+1;
    ssort(); get_h(); prework(); siz=sqrt(n);
    solve();
    for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
    for(int i=1;i<=n;i++) if(vis[i]) a[i]+=q-lst[i]+1;
    for(int i=1;i<=tot;i++) printf("%d ",a[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sizeof_you/article/details/85270719