1. 程式人生 > 其它 >P4070 [SDOI2016]生成魔咒(SAM)

P4070 [SDOI2016]生成魔咒(SAM)

技術標籤:字串演算法

傳送門

用字尾陣列做的真的心累

字尾陣列+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; } }