1. 程式人生 > >[BZOJ3926][ZJOI2015]諸神眷顧的幻想鄉(後綴自動機)

[BZOJ3926][ZJOI2015]諸神眷顧的幻想鄉(後綴自動機)

n-1 xtend ring LV hint 後綴 表示 lld 連接

日,無數幽香的粉絲到了幽香家門前的太陽花田上來為幽香慶祝生日。

粉絲們非常熱情,自發組織表演了一系列節目給幽香看。幽香當然也非常高興啦。 這時幽香發現了一件非常有趣的事情,太陽花田有n塊空地。在過去,幽香為了方便,在這n塊空地之間修建了n-1條邊將它們連通起來。也就是說,這n塊空地形成了一個樹的結構。 有n個粉絲們來到了太陽花田上。為了表達對幽香生日的祝賀,他們選擇了c中顏色的衣服,每種顏色恰好可以用一個0到c-1之間的整數來表示。並且每個人都站在一個空地上,每個空地上也只有一個人。這樣整個太陽花田就花花綠綠了。幽香看到了,感覺也非常開心。 粉絲們策劃的一個節目是這樣的,選中兩個粉絲A和B(A和B可以相同),然後A所在的空地到B所在的空地的路徑上的粉絲依次跳起來(包括端 點),幽香就能看到一個長度為A到B之間路徑上的所有粉絲的數目(包括A和B)的顏色序列。一開始大家打算讓人一兩個粉絲(註意:A,B和B,A是不同 的,他們形成的序列剛好相反,比如紅綠藍和藍綠紅)都來一次,但是有人指出這樣可能會出現一些一模一樣的顏色序列,會導致審美疲勞。 於是他們想要問題,在這個樹上,一共有多少可能的不同的顏色序列(子串)幽香可以看到呢? 太陽花田的結構比較特殊,只與一個空地相鄰的空地數量不超過20個。

Input

第一行兩個正整數n,c。表示空地數量和顏色數量。

第二行有n個0到c-1之間,由空格隔開的整數,依次表示第i塊空地上的粉絲的衣服顏色。(這裏我們按照節點標號從小到大的順序依次給出每塊空地上粉絲的衣服顏色)。 接下來n-1行,每行兩個正整數u,v,表示有一條連接空地u和空地v的邊。

Output

一行,輸出一個整數,表示答案。

Sample Input

7 3
0 2 1 2 1 0 0
1 2
3 4
3 5
4 6
5 7
2 5

Sample Output

30

HINT

對於所有數據,1<=n<=100000, 1<=c<=10。


對於15%的數據,n<=2000。
另有5%的數據,所有空地都至多與兩個空地相鄰。
另有5%的數據,除一塊空地與三個空地相鄰外,其他空地都分別至多與兩個空地相鄰。
另有5%的數據,除某兩塊空地與三個空地相鄰外,其他空地都分別至多與兩個空地相鄰

Source

[Submit][Status][Discuss]

SAM模板題,只要看出來字符串模型就行。註意要從葉子開始。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 typedef long long ll;
 6 using namespace std;
 7 
 8 const int N=200100,M=4000100;
 9 ll ans;
10 int tot=1,n,c,u,v,cnt,ind[N],a[N],son[M][11
],fa[M],mx[M],nxt[N],h[N],to[N]; 11 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 12 13 int extend(int p,int c){ 14 int np=++tot; mx[np]=mx[p]+1; 15 while (!son[p][c] && p) son[p][c]=np,p=fa[p]; 16 if (!p) fa[np]=1; 17 else{ 18 int q=son[p][c]; 19 if (mx[q]==mx[p]+1) fa[np]=q; 20 else{ 21 int nq=++tot; mx[nq]=mx[p]+1; 22 memcpy(son[nq],son[q],sizeof(son[q])); 23 fa[nq]=fa[q]; fa[np]=fa[q]=nq; 24 while (p && son[p][c]==q) son[p][c]=nq,p=fa[p]; 25 } 26 } 27 return np; 28 } 29 30 void solve(){ rep(i,1,tot) ans+=mx[i]-mx[fa[i]]; } 31 32 void dfs(int x,int fa,int p){ 33 int t=extend(p,a[x]); 34 for (int i=h[x]; i; i=nxt[i]) if (to[i]!=fa) dfs(to[i],x,t); 35 } 36 37 int main(){ 38 freopen("bzoj3926.in","r",stdin); 39 freopen("bzoj3926.out","w",stdout); 40 scanf("%d%d",&n,&c); 41 rep(i,1,n) scanf("%d",&a[i]); 42 rep(i,1,n-1) scanf("%d%d",&u,&v),add(u,v),add(v,u),ind[u]++,ind[v]++; 43 rep(i,1,n) if (ind[i]==1) dfs(i,0,1); 44 solve(); printf("%lld\n",ans); 45 return 0; 46 }

[BZOJ3926][ZJOI2015]諸神眷顧的幻想鄉(後綴自動機)