我学AC自动机的时候就看到了这题,想用AC自动机结果被学长码风劝退……

学后缀数组时又看到了这题……那就写写后缀数组做法吧 结果码风貌似比当年劝退我的学长还毒瘤啊

对所有的模式串+询问串,不同串之间用不同分隔符隔开,然后建后缀数组

第一问,显然所有包含询问串的后缀们的排名是一段连续的区间。于是就可以用ST表处理每两个后缀间的最长公共前缀,然后二分左端点和右端点。于是就变成了一个模板得不能再模板的,数一个区间中出现了多少个不同的数的莫队

第二问,考虑差分:每次询问时,如果一个串第一次出现,加上这个询问之后的询问个数,如果这个串将被删除,减掉这个询问之后的询问个数

代码:

#include <bits/stdc++.h>
#define M 420005
#define rep(i,x,y) for(i=(x);i<=(y);++i)
using namespace std;

int id[M],bg[M],n,m,sz=11000,ll[M];

namespace SA{
    int tp[M],tax[M],rnk[M],sa[M],height[M],len=0;
    int f[M][20],name[M];
    void init(){
        int i,j,x,y;
        scanf("%d%d",&n,&m);
        rep(i,1,n){
            rep(j,0,1){
                scanf("%d",&x);
                while(x--){
                    scanf("%d",&y);y++;
                    name[++len]=y,id[len]=i;
                }
                name[++len]=++sz;
                if(!j) id[len]=i;
            }
        }
        rep(i,1,m){
            scanf("%d",&x);
            ll[i]=x,bg[i]=len+1;
            while(x--){
                scanf("%d",&y);y++;
                name[++len]=y;
            }
            name[++len]=++sz;
        }sz++;
    }
    void Qsort(){
        int i;
        rep(i,0,sz) tax[i]=0;
        rep(i,1,len) tax[rnk[i]]++;
        rep(i,1,sz) tax[i]+=tax[i-1];
        for(i=len;i>=1;--i) sa[tax[rnk[tp[i]]]--]=tp[i];
    }
    inline bool cmp(int x,int y,int w){ return tp[x]==tp[y]&&tp[x+w]==tp[y+w]; }
    void SufSort(){
        int i,x;
        rep(i,1,len) rnk[i]=name[i],tp[i]=i;
        Qsort();
        for(x=1;x<=len;x<<=1){
            int num=0;
            rep(i,len-x+1,len) tp[++num]=i;
            rep(i,1,len) if(sa[i]>x) tp[++num]=sa[i]-x;
            Qsort();memcpy(tp,rnk,sizeof(tp));
            rnk[sa[1]]=1;
            rep(i,2,len) rnk[sa[i]]=rnk[sa[i-1]]+(!cmp(sa[i],sa[i-1],x));
            if(rnk[sa[len]]==len) return;
            sz=rnk[sa[len]];
        }
    }
    void GetHeight(){
        int i,j,k=0;
        memset(f,0x3f,sizeof(f));
        for(i=1;i<=len;++i){
            if(k) k--;
            int j=sa[rnk[i]-1];
            while(name[i+k]==name[j+k]) k++;
            height[rnk[i]]=f[rnk[i]][0]=k;
        }
        for(i=1;(1<<i)<=len;++i)
            for(j=1;j<=len;++j)
                f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);
    }
    int lcp(int x,int y){
        int l=x+1,r=y,w=log2(r-l+1);
        return min(f[l][w],f[r-(1<<w)+1][w]);
    }
}

namespace Query{
    int bl[M],t[M],tot=0,ans1[M],ans2[M],cnt=0;
    struct ques{
        int l,r,id;
        bool operator <(const ques &a)const{ return (bl[l]==bl[a.l])?(bl[l]&1?r>a.r:r<a.r):l<a.l; }
    }q[M];
    int getl(int x,int y){
        int l=1,r=x-1,ans=x;
        while(l<=r){
            int mid=l+r>>1;
            if(SA::lcp(mid,x)>=y) ans=mid,r=mid-1;
            else l=mid+1;
        }
        return ans;
    }
    int getr(int x,int y){
        int l=x+1,r=SA::len,ans=x;
        while(l<=r){
            int mid=l+r>>1;
            if(SA::lcp(x,mid)>=y) ans=mid,l=mid+1;
            else r=mid-1;
        }
        return ans;
    }
    void init(){
        int i,n=SA::len,block=sqrt(n);
        rep(i,1,n) bl[i]=(i-1)/block+1;
        rep(i,1,m){
            int L=getl(SA::rnk[bg[i]],ll[i]),R=getr(SA::rnk[bg[i]],ll[i]);
            if(L<=R)q[++cnt]=(ques){L,R,i};
//          printf("%d : %d %d\n",i,L,R);
        }
    }
    inline void add(int x,int y){
        if(++t[id[SA::sa[x]]]==1 && id[SA::sa[x]])
            tot++,ans2[id[SA::sa[x]]]+=m-y+1;
    }
    inline void del(int x,int y){
        if(--t[id[SA::sa[x]]]==0 && id[SA::sa[x]])
            tot--,ans2[id[SA::sa[x]]]-=m-y+1;
    }
    void solve(){
        sort(q+1,q+cnt+1);
        memset(t,0,sizeof(t));
        int i,L=1,R=0;
        rep(i,1,cnt){
            while(R<q[i].r) add(++R,i);
            while(L>q[i].l) add(--L,i);
            while(R>q[i].r) del(R--,i);
            while(L<q[i].l) del(L++,i);
            ans1[q[i].id]=tot;
        }
        rep(i,1,m) printf("%d\n",ans1[i]);
        rep(i,1,n) printf("%d ",ans2[i]);
    }
}

int main(){
    SA::init();
    SA::SufSort();
    SA::GetHeight();
    Query::init();
    Query::solve();
} 

洛谷P2336 [SCOI2012]喵星球上的点名(后缀数组+莫队)的更多相关文章

  1. 洛谷 P2336 [SCOI2012]喵星球上的点名 解题报告

    P2336 [SCOI2012]喵星球上的点名 题目描述 a180285 幸运地被选做了地球到喵星球的留学生.他发现喵星人在上课前的点名现象非常有趣. 假设课堂上有 \(N\) 个喵星人,每个喵星人的 ...

  2. P2336 [SCOI2012]喵星球上的点名(SA+莫队)

    题面传送门 一道还算有点含金量的 SA 罢-- 首先按照套路我们把读入的所有字符串都粘在一起,中间用分隔符隔开并建出后缀数组出来. 我们考虑对于一个固定的字符串 \(s\),什么样的字符串 \(t\) ...

  3. 洛咕 P2336 [SCOI2012]喵星球上的点名

    洛咕 P2336 [SCOI2012]喵星球上的点名 先求出SA和height,一个点名串对应的就是一段区间,还有很多个点,就转化成了 有很多个区间,很多个点集,对每个区间计算和多少个点集有交,对每个 ...

  4. BZOJ 2754: [SCOI2012]喵星球上的点名 [后缀数组+暴力]

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1906  Solved: 839[Submit][St ...

  5. Luogu2336 SCOI2012 喵星球上的点名 SA、莫队

    传送门 一道很套路的题目 先将所有串拼在一起,两个不同的串之间放一个没有出现在任何串中的字符做分隔,然后SA 那么对于所有点名串能够点到的名字串在SA中对应一段区间 把这些区间拿出来然后莫队统计每一个 ...

  6. P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队+dfs序)

    P2336 [SCOI2012]喵星球上的点名 名字怎么存?显然是后缀自动机辣 询问点到多少个喵喵喵其实就是 查询后缀自动机上parent树的一个子树 于是我们考虑莫队 怎么树上莫队呢 我们用dfs序 ...

  7. BZOJ 2754 SCOI 2012 喵星球上的点名 后缀数组 树状数组

    2754: [SCOI2012]喵星球上的点名 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 2068  Solved: 907[Submit][St ...

  8. Luogu P2336 [SCOI2012]喵星球上的点名

    题目链接 \(Click Here\)_ \(200\)行纯干货的代码,一发\(WA\)掉真的是让人窒息,幸好最后找到了锅在哪.(差点就要弃掉了\(QAQ\)) [调出来的时候真的是要高兴到哭出来了\ ...

  9. 【BZOJ2754】[SCOI2012]喵星球上的点名

    [BZOJ2754][SCOI2012]喵星球上的点名 题面 bzoj 洛谷 题解 这题有各种神仙做法啊,什么暴力\(AC\)自动机.\(SAM\)等等五花八门 我这个蒟蒻在这里提供一种复杂度正确且常 ...

随机推荐

  1. zoj 1760 查找

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=760 撸了个二分查找 #include<iostream> #inc ...

  2. UOJ#55 [WC2014]紫荆花之恋

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上是一个带权树. ...

  3. jquery特效:无缝向上循环滚动列表

    效果呈现 整个列表间隔设定的时间向上移动一个item的高度 html结构: <div class="slide-title"> <span>title1&l ...

  4. C语言——无向带权图邻接矩阵的建立

    #include <stdio.h> #include "Graph.h" #define MAX_INT 32767 /* #define vnum 20 #defi ...

  5. 简析 Tomcat 、Nginx 与 Apache 的区别

    简析 Tomcat .Nginx 与 Apache 的区别 本文讲的是简析 Tomcat .Nginx 与Apache的区别, 经常在用 apache 和 tomcat 等这些服务器,可是总感觉还是不 ...

  6. 对View的onMeasure()方法的进一步研究

    在Android开发中,很多人对自定义View是望而生畏,但这又是向高级进阶的必经之路,主要是对View里面的很多方法不知道怎么理解,其中一个就是onMeasure()方法. 首先,我自定义一个MyV ...

  7. Forword与sendRedirect的区别

    二.本质区别 解释一 一句话,转发是服务器行为,重定向是客户端行为.为什么这样说呢,这就要看两个动作的工作流程: 转发过程:客户浏览器发送http请求——>web服务器接受此请求——>调用 ...

  8. svn提示out of date的解决方法

    步骤1. team–>update 步骤2. team–>Show Tree Conflict–>标记"冲突已解决" 步骤3. team–>commit

  9. Delphi XE7功能之TMultiView

    TMultView,做为一个TPanel来显示控件,可通过属性Mode来控制TMultView的显示效果,如下拉或者以抽屉方式.从屏一侧象抽屉一样显示TMultView,但不会转换主屏,也就是说在主窗 ...

  10. linux的pthread_self与gettid的返回值和开销的区别

    linux的pthread_self与gettid的返回值和开销的区别 linux的pthread_self与gettid的返回值和开销的区别 分类: 一些思考 2012-05-18 12:25 17 ...