【bzoj5084】hashit 广义后缀自动机+树链的并+STL-set
生活随笔
收集整理的這篇文章主要介紹了
【bzoj5084】hashit 广义后缀自动机+树链的并+STL-set
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題目描述
你有一個(gè)字符串S,一開始為空串,要求支持兩種操作 在S后面加入字母C 刪除S最后一個(gè)字母 問每次操作后S有多少個(gè)兩兩不同的連續(xù)子串輸入
一行一個(gè)字符串Q,表示對(duì)S的操作 如果第i個(gè)字母是小寫字母c,表示第一種加字母c的操作 如果為-表示刪除操作,保證所有刪除操作前S都非空 |Q|<=10^5輸出
輸出|Q|行,第i行表示i個(gè)操作之后S內(nèi)有多少個(gè)不同子串樣例輸入
aba-caba
樣例輸出
1
3
5?
3?
6?
9
12
17
題解
廣義后綴自動(dòng)機(jī)+樹鏈的并+STL-set
題目給出的字符串是一棵Trie的形式,我們對(duì)其建出廣義后綴自動(dòng)機(jī)。
那么每次我們要求的就是:Trie樹上當(dāng)前所有點(diǎn)在后綴自動(dòng)機(jī)pre樹到根節(jié)點(diǎn)的路徑所覆蓋的所有點(diǎn)的 $dis[pre[i]]-dis[i]$ 之和,即樹鏈的并的長度。
我們使用STL-set維護(hù)動(dòng)態(tài)插入刪除節(jié)點(diǎn)的樹鏈的并即可。
時(shí)間復(fù)雜度 $O(26n+n\log n)$ 。
第一次寫正常的廣義SAM = =
#include <set> #include <cstdio> #include <cstring> #include <algorithm> #define N 200010 using namespace std; set<int> s; set<int>::iterator it; char str[N]; int tc[N][26] , tf[N] , tt = 1 , pos[N] , c[N][26] , pre[N] , dis[N] , tot = 1 , head[N] , to[N] , next[N] , cnt , fa[N][20] , deep[N] , log[N] , vp[N] , rp[N] , tp; inline int insert(int x , int p) {if(c[p][x]){int q = c[p][x];if(dis[q] == dis[p] + 1) return q;else{int nq = ++tot;memcpy(c[nq] , c[q] , sizeof(c[q]));dis[nq] = dis[p] + 1 , pre[nq] = pre[q] , pre[q] = nq;while(p && c[p][x] == q) c[p][x] = nq , p = pre[p];return nq;}}else{int np = ++tot;dis[np] = dis[p] + 1;while(p && !c[p][x]) c[p][x] = np , p = pre[p];if(!p) pre[np] = 1;else{int q = c[p][x];if(dis[q] == dis[p] + 1) pre[np] = q;else{int nq = ++tot;memcpy(c[nq] , c[q] , sizeof(c[q]));dis[nq] = dis[p] + 1 , pre[nq] = pre[q] , pre[np] = pre[q] = nq;while(p && c[p][x] == q) c[p][x] = nq , p = pre[p];}}return np;} } void build(int x) {int i;for(i = 0 ; i < 26 ; i ++ )if(tc[x][i])pos[tc[x][i]] = insert(i , pos[x]) , build(tc[x][i]); } inline void add(int x , int y) {to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt; } void dfs(int x) {int i;vp[x] = ++tp , rp[tp] = x;for(i = 1 ; i <= log[deep[x]] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];for(i = head[x] ; i ; i = next[i]) fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]); } inline int lca(int x , int y) {int i;if(deep[x] < deep[y]) swap(x , y);for(i = log[deep[x] - deep[y]] ; ~i ; i -- )if(deep[x] - deep[y] >= (1 << i))x = fa[x][i];if(x == y) return x;for(i = log[deep[x]] ; ~i ; i -- )if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i])x = fa[x][i] , y = fa[y][i];return fa[x][0]; } int main() {int q , i , now = 1 , x , y;long long ans = 0;scanf("%s" , str) , q = strlen(str);for(i = 0 ; i < q ; i ++ ){if(str[i] == '-') now = tf[now];else{if(!tc[now][str[i] - 'a']) tc[now][str[i] - 'a'] = ++tt , tf[tt] = now;now = tc[now][str[i] - 'a'];}}pos[1] = 1 , build(1);for(i = 2 ; i <= tot ; i ++ ) add(pre[i] , i) , log[i] = log[i >> 1] + 1;dfs(1);now = 1;for(i = 0 ; i < q ; i ++ ){if(str[i] == '-'){ans -= dis[pos[now]] , s.erase(vp[pos[now]]);x = y = 0 , it = s.upper_bound(vp[pos[now]]);if(it != s.end()) x = rp[*it];if(it != s.begin()) y = rp[*--it];if(x) ans += dis[lca(pos[now] , x)];if(y) ans += dis[lca(pos[now] , y)];if(x && y) ans -= dis[lca(x , y)];now = tf[now];}else{now = tc[now][str[i] - 'a'] , ans += dis[pos[now]];x = y = 0 , it = s.upper_bound(vp[pos[now]]);if(it != s.end()) x = rp[*it];if(it != s.begin()) y = rp[*--it];if(x) ans -= dis[lca(pos[now] , x)];if(y) ans -= dis[lca(pos[now] , y)];if(x && y) ans += dis[lca(x , y)];s.insert(vp[pos[now]]);}printf("%lld\n" , ans);}return 0; }?
?
轉(zhuǎn)載于:https://www.cnblogs.com/GXZlegend/p/8711038.html
總結(jié)
以上是生活随笔為你收集整理的【bzoj5084】hashit 广义后缀自动机+树链的并+STL-set的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是跨域,什么是同源
- 下一篇: [ERR] Not all 16384