BZOJ 2780 Sevenk Love Oimaster (后缀自动机+树状数组+dfs序+离线)

题目大意:

给你$n$个大串和$m$个询问,每次给出一个字符串$s$询问在多少个大串中出现过

好神的一道题

对$n$个大串建出广义$SAM$,建出$parent$树

把字符串$s$放到$SAM$里跑,找到能表示字符串$s$的节点$x$

问题转化为在$parent$树中,$x$节点的子树内,有多少个编号不同的$endpos$节点

把树拍扁,转化为$dfs$序

不就是在序列上跑HH的项链么,离线树状数组维护一下就好

一个节点可能有多个不同串$endpos$标记,用$vector$存一下串的编号就行了

注意索引不要写错,不要把数组开小了

  1 #include <vector>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 105000
  6 #define S1 (N1<<1)
  7 #define T1 (N1<<2)
  8 #define ll long long
  9 #define uint unsigned int
 10 #define rint register int 
 11 #define il inline 
 12 #define inf 0x3f3f3f3f
 13 #define idx(X) (X-'a')
 14 using namespace std;
 15 
 16 int gint()
 17 {
 18     int ret=0,fh=1;char c=getchar();
 19     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 20     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 21     return ret*fh;
 22 }
 23 
 24 int n,m,len,tot;
 25 char str[N1];
 26 struct Edge{
 27 int to[T1],nxt[T1],head[T1],cte;
 28 void ae(int u,int v){
 29     cte++;to[cte]=v;nxt[cte]=head[u],head[u]=cte;}
 30 }E,Q;
 31 struct BIT{
 32 int sum[T1],ma;
 33 void upd(int x,int w){
 34     for(int i=x;i<=ma;i+=(i&(-i)))
 35         sum[i]+=w;}
 36 int query(int x){
 37     int ans=0;
 38     for(int i=x;i>0;i-=(i&(-i)))
 39         ans+=sum[i];
 40     return ans;}
 41 }b;
 42 namespace SAM{
 43 int trs[S1][26],pre[S1],dep[S1],la;
 44 vector<int>ed[S1];
 45 void init(){tot=la=1;}
 46 void reduct(){la=1;}
 47 void insert(int x,int id)
 48 {
 49     int p=la,q,np=++tot,nq;la=np;
 50     dep[np]=dep[p]+1;
 51     ed[np].push_back(id);
 52     for(;p&&!trs[p][x];p=pre[p]) trs[p][x]=np;
 53     if(!p) pre[np]=1;
 54     else{
 55         q=trs[p][x];
 56         if(dep[q]==dep[p]+1) pre[np]=q;
 57         else{
 58             pre[nq=++tot]=pre[q];
 59             pre[q]=pre[np]=nq;
 60             dep[nq]=dep[p]+1;
 61             memcpy(trs[nq],trs[q],sizeof(trs[q]));
 62             for(;p&&trs[p][x]==q;p=pre[p]) trs[p][x]=nq;
 63         }
 64     }
 65 }
 66 void Build_Edge()
 67 {
 68     for(int i=2;i<=tot;i++)
 69         E.ae(pre[i],i);
 70 }
 71 int find(char *str,int L)
 72 {
 73     int x=1;
 74     for(int i=1;i<=L;i++){
 75         x=trs[x][idx(str[i])];
 76         if(!x) return 0;
 77     }return x;
 78 }
 79 };
 80 namespace Seq{
 81 int st[T1],ed[T1],to[T1],ans[T1],la[T1],cnt;
 82 void dfs1(int x)
 83 {
 84     st[x]=++cnt;
 85     for(int j=E.head[x];j;j=E.nxt[j])
 86         dfs1(E.to[j]);
 87     ed[x]=++cnt;
 88     to[cnt]=x;
 89 }
 90 void solve()
 91 {
 92     dfs1(1);
 93     b.ma=cnt;
 94     int x,v;
 95     for(int i=1;i<=m;i++)
 96     {
 97         scanf("%s",str+1);
 98         len=strlen(str+1);
 99         x=SAM::find(str,len);
100         if(x) Q.ae(ed[x],i);
101     }
102     for(int i=1;i<=cnt;i++)
103     {
104         x=to[i];
105         for(int j=0;j<SAM::ed[x].size();j++)
106         {
107             v=SAM::ed[x][j];
108             if(!la[v]) b.upd(i,1),la[v]=i;
109             else b.upd(la[v],-1),la[v]=i,b.upd(i,1);
110         }
111         for(int j=Q.head[i];j;j=Q.nxt[j])
112         {
113             v=Q.to[j];
114             ans[v]=b.query(ed[x])-b.query(st[x]);
115         }
116     }
117     for(int i=1;i<=m;i++)
118         printf("%d\n",ans[i]);
119 }
120 
121 };
122 
123 int main()
124 {
125     //freopen("t2.in","r",stdin);
126     scanf("%d%d",&n,&m);
127     SAM::init();
128     for(int i=1;i<=n;i++)
129     {
130         scanf("%s",str+1);
131         len=strlen(str+1);
132         for(int j=1;j<=len;j++)
133             SAM::insert(idx(str[j]),i);
134         SAM::reduct();
135     }
136     SAM::Build_Edge();
137     Seq::solve();
138     return 0;
139 }

 

posted @ 2018-12-10 18:48  guapisolo  阅读(164)  评论(0编辑  收藏  举报