BZOJ1396 識別子串 SAM 線段樹

2021-09-02 18:01:05 字數 3034 閱讀 5398

題目鏈結

題意:給定乙個字串s,對於乙個整數k,定義s的子串t=s(i, j)是關於第k位的識別子串,滿足以下兩個條件:

1、i≤k≤j。

2、子串t只在s中出現過一次。

例如,s=「banana」,k=5,則關於第k位的識別子串有"nana",「anan」,「anana」,「nan」,「banan"和"banana」。

現在,給定s,求對於s的每一位,最短的識別子串長度是多少

題解:建出sam,我們發現可以作為識別子串需要只出現一次,所以就是sam的parent樹上的葉子節點。我們設l=l

en[i

]−le

n[fa

[i]]

l=len[i]-len[fa[i]]

l=len[

i]−l

en[f

a[i]

],r=le

n[i]

r=len[i]

r=len[

i],那麼對於i∈[

l,r]

i\in[l,r]

i∈[l,r

],ans[

i]=m

in=r

−l+1

ans[i]=min\=r-l+1

ans[i]

=min

=r−l

+1。因為父節點代表的串在子節點又出現過了,所以最短沒出現的就是父節點+1。

對於i ∈[

1,l)

i\in[1,l)

i∈[1,l

),因為[l,

r]

[l,r]

[l,r

]這一段是唯一的,所以加上乙個字首後仍是唯一的,於是可以用每個i

ii到r

rr的長度來更新答案,即r−i

+1

r-i+1

r−i+

1。而我們在回答時,i

ii是已知的,所以不用維護這個i

ii,我們只需要對每個位置維護最小的r

rr就行了。

於是我們需要開兩棵線段樹,分別維護兩種情況的答案,然後取個min即可。

**:

#include

using

namespace std;

int n,fa[

400010

],ch[

400010][

26],len[

400010

],sz[

400010

],lst=

1,rt=

1,cnt=1;

int vis[

400010];

char s[

100010];

struct node

tr1[

1600010

],tr2[

1600010];

inline

void

insert

(int x)}}

inline

void

build

(int rt,

int l,

int r)

int mid=

(l+r)

>>1;

build

(rt<<

1,l,mid)

;build

(rt<<1|

1,mid+

1,r)

; tr1[rt]

.mn=

2e9;

tr2[rt]

.mn=

2e9;

}inline

void

pushdown1

(int rt)

inline

void

update1

(int rt,

int le,

int ri,

int x)

pushdown1

(rt)

;int mid=

(l+r)

>>1;

if(le<=mid)

update1

(rt<<

1,le,ri,x);if

(mid+

1<=ri)

update1

(rt<<1|

1,le,ri,x)

; tr1[rt]

.mn=

min(tr1[rt<<1]

.mn,tr1[rt<<1|

1].mn);}

inline

void

pushdown2

(int rt)

inline

void

update2

(int rt,

int le,

int ri,

int x)

pushdown2

(rt)

;int mid=

(l+r)

>>1;

if(le<=mid)

update2

(rt<<

1,le,ri,x);if

(mid+

1<=ri)

update2

(rt<<1|

1,le,ri,x)

; tr2[rt]

.mn=

min(tr2[rt<<1]

.mn,tr2[rt<<1|

1].mn);}

inline

intquery1

(int rt,

int x)

inline

intquery2

(int rt,

int x)

intmain()

}for

(int i=

1;i<=n;

++i)

printf

("%d\n"

,min

(query1(1

,i),

query2(1

,i)-i+1)

);return0;

}

bzoj1396識別子串(SAM 線段樹)

複習sam板子啦!考前刷水有益身心健康當然這不是板子題 水題 很容易發現只在i位置出現的串一定是個字首串。那麼對答案的貢獻分成兩部分 一部分是len x fa len x 的這部分貢獻會是r l 1 剩下一部分1 len fa 1這部分會和i r構成答案,寫兩棵線段樹即可。然後就又是板子題了,兩個板...

BZOJ 1396 識別子串

solution 我得了 能用字尾陣列就一定不用字尾自動機綜合症 感覺用height rank sa 處理字串真的好優雅 雖然其他題上字尾陣列常數比較大 不過這個字尾陣列水了一發似乎就rank1 了 開心 題解就是求出字尾陣列以後維護乙個單調佇列來更新答案啦。include include incl...

Bzoj1396 識別子串

i 1,n i 1,n 求包含 i i 並且在原串 s role presentation style position relative s s中只出現一次的子串的最短長度 因為每個點pa rent p ar en t樹上的父親肯定是當前節點所代表的串的字尾 那麼只出現一次的串就是pa rent ...