1. 程式人生 > >BZOJ 2780 Sevenk Love Oimaster (字尾自動機+樹狀陣列+dfs序+離線)

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 }