Bzoj2534 字尾自動機 主席樹啟發式合併

2022-05-02 02:15:12 字數 2122 閱讀 6358

國際慣例的題面:

考慮我們求解出字串uvu第乙個u的右端點為i,第二個u的右端點為j,我們需要滿足什麼性質?

顯然j>i+l,因為我們選擇的串不能是空串。

另外考慮i和j的最長公共字首(也就是說其parent樹上lca的len),為了保證他們相同,我們需要:

j-len>=i-l。

整理一下,如果我們已知i,j需要在區間[i+l+1,i+l+len]中。

如果我們已知j,i需要在區間[j-l-len,j-l-1]中。

於是我們可以寫n^2暴力了:暴力維護parent上每個節點的right集合,對於每個i,暴力向上跳,暴力找可行的j。

然後我們發現,維護right集合可以用主席樹啟發式合併做,對於計算貢獻,我們可以先列舉lca,然後計算有多少組可行的i,j。

在第二個計算的時候,我們顯然是會在兩顆主席樹進行合併的時候進行計算,於是我們可以把較小的那顆拍扁,在另外一棵裡暴力查詢每乙個值的貢獻。

這樣總複雜度o(nlog^2n),輕鬆ac。

注意主席樹啟發式合併的時間和空間複雜度都是o(nlog^n)的,因為考慮每層攤還下來只會被新建logn次(我已經把長度和節點個數乘起來了)。

另外這題字符集大小為全體可見字元,所以需要用map存字尾自動機。

(不是很明白為什麼網上那麼多題解都是字尾陣列的,明明字尾自動機這麼好寫(不會字尾陣列的就不要說話了.jpg))

**:

1 #include2 #include3 #include4 #include5

using

namespace

std;

6const

int maxn=1e5+1e2,maxl=18;7

8char

in[maxn>>1];9

intli,lim;

10int seq[maxn>>1

],seqlen;

11long

long

ans;

1213

struct

persistentsegmenttree

22 inline int merge(int p1,int p2,int l,int

r) 31 inline int query(int pos,int l,int r,const

int &ll,const

int &rr)

39 inline void dfs(int pos,int l,int

r) 45 inline int getsiz(int

pos)

48}segt;

4950

namespace

sam

58 inline int extend(int x,int

rr) 72}

73return last =np;74}

75 inline int query(int root,int i,int

samelen)

81 inline void

topo()

93if( segt.getsiz(roots[fa[pos]]) < segt.getsiz(roots[pos]) ) //

we won't use roots[pos] again .

94swap(roots[fa[pos]],roots[pos]);

95 seqlen = 0 , segt.dfs(roots[pos],1

,li);

96for(int i=1;i<=seqlen;i++) ans +=query(roots[fa[pos]],seq[i],len[fa[pos]]);

97 roots[fa[pos]] = segt.merge(roots[fa[pos]],roots[pos],1

,li);

98if( !--deg[fa[pos]] ) q.push(fa[pos]);99}

100}

101}

102103

intmain()

view code

bzoj3998 字尾自動機

對於乙個給定長度為n的字串,求它的第k小子串是什麼。第一行是乙個僅由小寫英文本母構成的字串s 第二行為兩個整數t和k,t為0則表示不同位置的相同子串算作乙個。t 1則表示不同位置的相同子串算作多個。k的意義如題所述。輸出僅一行,為乙個數字串,為第k小的子串。如果子串數目不足k個,則輸出 1 aabc...

BZOJ 2780 字尾自動機

由於是英文題,簡要解釋一下題目。開始給出n個子串,和m個詢問,對於每個詢問讀入乙個子串,詢問n個子串中,有多少個子串包含所詢問的子串。實在看不懂的可以從樣例中意會一下。include include include include include include using namespace st...

BZOJ 4516 字尾自動機

題意 統計本質不同的子串數量。題解 模板題,字尾自動機。在每乙個節點處,統計一下他能代表多少個 以他為終點的串。然後動態建立sam,同時每加一次都輸出一次就行了。唯一的不同是,這個題是int,而不是傳統的字串,那麼把nxt陣列換成map,複雜度多乙個log sizeof nxt 實際上非常小。cod...