P4070 [SDOI2016]生成魔咒(SAM)
阿新 • • 發佈:2021-02-20
技術標籤:字串演算法
用字尾陣列做的真的心累
字尾陣列+ST表+反串思維+set(或平衡樹)動態維護 h e i g h t height height陣列
然後用 S A M SAM SAM就是模板題…
要求本質不同的子串有多少個
也就是每個 e n d p o s endpos endpos類的元素個數和
每個 e n d p o s endpos endpos有 l e n [ p ] − l e n [ f a p ] len[p]-len[fa_p] len[p]−len[fap]串,累加即可
由於 S A M SAM SAM是個線上演算法,動態插入即可
每次修改一個節點父親的時候就需要重新計算貢獻(減去原來的加上現在的)
不過有意思的是,新建的 n q nq nq節點並不會改變原來的值
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e6+10;
char s[maxn];
struct SAM
{
map<int,int>zi;
int len,fa;
}sam[maxn]; int las = 1,id = 1;
long long ans = 0;
void insert(int c)
{
int p = las, np = ++id; las = id;
sam[np].len = sam[p]. len + 1;
for( ; p&&!sam[p].zi[c];p=sam[p].fa ) sam[p].zi[c] = np;
if( p==0 ) sam[np].fa = 1,ans += sam[np].len-sam[sam[np].fa].len;
else
{
int q = sam[p].zi[c];
if( sam[q].len==sam[p].len+1 ) sam[np].fa = q,ans += sam[np].len-sam[sam[np].fa].len;
else
{
int nq = ++id;
sam[nq] = sam[q], sam[nq].len = sam[p].len+1;
ans += sam[nq].len-sam[sam[nq].fa].len;
ans -= sam[q].len-sam[sam[q].fa].len;
sam[q].fa = sam[np].fa = nq;
ans += sam[q].len-sam[sam[q].fa].len;
ans += sam[np].len-sam[sam[np].fa].len;
for( ; p&&sam[p].zi[c]==q;p=sam[p].fa ) sam[p].zi[c] = nq;
}
}
}
int main()
{
int n; cin >> n;
for(int i=1;i<=n;i++)
{
int x; cin >> x;
insert( x );
cout << ans << endl;
}
}