之前我们给的SAM的例题,基本上是一个串建SAM的就能做的

如果要建多个串的SAM应该怎么做呢

首先看题,bzoj2780

我一开始的想法是SA以前的弄法,把串拼起来,中间加分隔符做SAM

这题确实可以这么做,这样根据SAM能识别所有子串的性质

而且每个节点都代表了唯一的一个串

每个询问串我们都能找到最终转移到哪(找不到就是没出现过)

问在多少个串出现过这就等价于在ST(s)的parent树的子树中,出现了多少种不同的权值

这显然可以维护dfs序,用经典的离线做法来搞(更好的写法见文末UPD)

  1 type node=record
  2        po,next:longint;
  3      end;
  4 
  5 var go:array[0..300010,1..27] of longint;
  6     d,mx,fa,l,r,p,c,wh,w,fir,next:array[0..300010] of longint;
  7     ans,a,b:array[0..60010] of longint;
  8     e:array[0..300010] of node;
  9     h,t,k,last,len,i,j,n,q,x:longint;
 10     s,ss:ansistring;
 11 
 12 function lowbit(x:longint):longint;
 13   begin
 14     exit(x and (-x));
 15   end;
 16 
 17 function cmp(a,b:longint):boolean;
 18   begin
 19     exit(l[a]<l[b]);
 20   end;
 21 
 22 procedure swap(var a,b:longint);
 23   var c:longint;
 24   begin
 25     c:=a;
 26     a:=b;
 27     b:=c;
 28   end;
 29 
 30 procedure sort(l,r:longint);
 31   var i,j,x:longint;
 32   begin
 33     i:=l;
 34     j:=r;
 35     x:=a[(l+r) shr 1];
 36     repeat
 37       while cmp(a[i],x) do inc(i);
 38       while cmp(x,a[j]) do dec(j);
 39       if not(i>j) then
 40       begin
 41         swap(a[i],a[j]);
 42         swap(b[i],b[j]);
 43         inc(i);
 44         dec(j);
 45       end;
 46     until i>j;
 47     if l<j then sort(l,j);
 48     if i<r then sort(i,r);
 49   end;
 50 
 51 procedure build(x,y:longint);
 52   begin
 53     inc(len);
 54     e[len].po:=y;
 55     e[len].next:=p[x];
 56     p[x]:=len;
 57   end;
 58 
 59 procedure add(c,x:longint);
 60   var p,q,np,nq:longint;
 61   begin
 62     p:=last;
 63     inc(t); last:=t; np:=t;
 64     w[np]:=x; mx[np]:=mx[p]+1;
 65     while (p<>0) and (go[p,c]=0) do
 66     begin
 67       go[p,c]:=np;
 68       p:=fa[p];
 69     end;
 70     if p=0 then fa[np]:=1
 71     else begin
 72       q:=go[p,c];
 73       if mx[q]=mx[p]+1 then fa[np]:=q
 74       else begin
 75         inc(t); nq:=t;
 76         mx[nq]:=mx[p]+1;
 77         go[nq]:=go[q];
 78         fa[nq]:=fa[q];
 79         fa[q]:=nq; fa[np]:=nq;
 80         while go[p,c]=q do
 81         begin
 82           go[p,c]:=nq;
 83           p:=fa[p];
 84         end;
 85       end;
 86     end;
 87   end;
 88 
 89 procedure dfs(x:longint);
 90   var i:longint;
 91   begin
 92     inc(h);
 93     l[x]:=h;
 94     d[h]:=w[x];  //dfs序
 95     i:=p[x];
 96     while i<>0 do
 97     begin
 98       dfs(e[i].po);
 99       i:=e[i].next;
100     end;
101     r[x]:=h;
102   end;
103 
104 procedure work(x:longint);
105   begin
106     while x<=t do
107     begin
108       inc(c[x]);
109       x:=x+lowbit(x);
110     end;
111   end;
112 
113 function ask(x:longint):longint;
114   begin
115     ask:=0;
116     while x>0 do
117     begin
118       ask:=ask+c[x];
119       x:=x-lowbit(x);
120     end;
121   end;
122 
123 begin
124   readln(n,q);
125   for i:=1 to n do
126   begin
127     readln(ss);
128     len:=length(ss);
129     for j:=1 to len do  //拼接
130     begin
131       s:=s+ss[j];
132       inc(t); wh[t]:=i;
133     end;
134     if i<>n then
135     begin
136       s:=s+chr(97+26);
137       inc(t);
138     end;
139   end;
140   len:=length(s);
141   t:=1; last:=1;
142   for i:=len downto 1 do
143     add(ord(s[i])-96,wh[i]);
144 
145   len:=0;
146   for i:=2 to t do  //构建树
147     build(fa[i],i);
148 
149   dfs(1);
150   for i:=1 to q do
151   begin
152     readln(s);
153     j:=1;
154     len:=length(s);
155     for k:=len downto 1 do  //每个询问串最终转移到哪
156     begin
157       x:=ord(s[k])-96;
158       if go[j,x]=0 then
159       begin
160         j:=0;
161         break;
162       end
163       else j:=go[j,x];
164     end;
165     a[i]:=j;
166     b[i]:=i;
167   end;
168   for i:=t downto 2 do  //经典的离线做法
169   begin
170     next[i]:=fir[d[i]];
171     fir[d[i]]:=i;
172   end;
173   for i:=1 to n do
174     if fir[i]<>0 then work(fir[i]);
175   sort(1,q);
176   j:=1;
177   while a[j]=0 do inc(j);
178   for i:=1 to t do
179   begin
180     while (j<=q) and (l[a[j]]=i) do
181     begin
182       ans[b[j]]:=ask(r[a[j]])-ask(i-1);
183       inc(j);
184     end;
185     if d[i]<>0 then
186       if next[i]<>0 then work(next[i]);
187   end;
188   for i:=1 to q do
189     writeln(ans[i]);
190 end.
2780

相关文章: