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 }