考慮怎麼算答案。
首先本質不同子串個數大概就是幾種做法,字尾陣列,字尾自動機,暴力
然後字尾自動機。。。眾所周知,並沒有區間字尾自動機這種扯淡的資料結構。
換乙個思路,我們並不直接統計,而是對於前面每乙個重複出現的字串,打上-1標記。
仔細想一想即可得到本題正解。
怎麼得到重複字串,顯然是sam跳fail鏈,每個點維護right集合最大值,更新之前先把前面的-1打上標記,對於每個右端點可持久化一下,主席樹標記永久化維護區間加區間求和。
發現right集合最大值相同的更新起來的是連續的,直接用lct維護最大值相同的鏈,那麼新加乙個點直接access,在access的同時在主席樹裡面修改即可。
由finger search 理論,複雜度只有乙個o(n
logn)
o(n\log n)
o(nlogn)
最後實現注意一下字串邊界,lct稍微考慮一下可以不用寫cut。
其實就是在斷掉父親和它之間的實邊之後,將它splay,然後直接改父親指標,也就是子樹換父親(我真tm機智)。
**:
#include
#define ll long long
#define re register
#define cs const
namespace io
inline
char
peek()
inline
charga(
)template
<
typename t>
inline t get()
inline
intgi()
inline ll gl()
}using
namespace io;
using std::cerr;
using std::cout;
cs int n=
1e5+7;
int m;
namespace pst
inline
void
ins(
int&u,
int l,
int r,
int ql,
int qr,
int v)
int mid=l+r>>1;
if(ql<=mid)
ins(lc[u]
,l,mid,ql,qr,v);if
(midins(rc[u]
,mid+
1,r,ql,qr,v);}
inline ll query
(int u,
int l,
int r,
int ql,
int qr)
}int rt[n]
;namespace lct
inline
void
pushdown
(int u)
}inline
bool
isrt
(int u)
inline
bool
which
(int u)
inline
void
rotate
(int u)
inline
void
splay
(int u)
inline
void
access
(int u,
int id)
son[u][1
]=ch;
}pushtag
(ch,id);}
inline
intget
(int u)
inline
void
link
(int u,
int f)
}int nowl;
namespace sam
inline
void
push_back
(int c)}}
ll ans;
int n,m,op;
char s[n]
;inline
void
ins(
)inline
void
query()
#ifdef zxyoi
#undef zxyoi
#endif
signed
main()
}return0;
}
BJ模擬 String(SAM LCT 主席樹)
傳送門 題意 給字串 s s 支援 1.末尾加入字元。2.查詢 l r role presentation l,r l r 中出現兩次的最長字串。題解 好題。考慮離線做法 動態插入後面的字元,更新前面 l l 的答案。當我們插入乙個字元 r role presentation r r的時候,與前面的...
聯賽模擬測試5 序列 主席樹
對於每乙個位置,我們開一棵權值線段樹,記錄這個位置上的每乙個取值對答案的貢獻 對於每一次詢問,對它有貢獻的點是區間 l,r 中大於等於 x 的數 因此我們考慮差分,在 l 的位置 1 在 r 1 的位置 1 轉換到具體的點上,就是當點的座標恰好為 l 在 x 的位置 1 恰好為 r 1 在 x 的位...
校內模擬 層流 樹鏈剖分
給出一棵樹,給出n條邊,問這些邊兩兩之間是否滿足兩個條件之一 覆蓋對方或被對方覆蓋 沒有相交。如果都滿足輸出yes,否則輸出no。題解考場上第一眼就覺得是樹剖,畢竟前段時間天天見到這種型別的東西。做法有點差分的意思,在每條邊的兩個頂點異或上某個值,然後查詢這條邊上的異或和,如果合法異或和當然為0。但...