BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)
生活随笔
收集整理的這篇文章主要介紹了
BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目鏈接: https://www.lydsy.com/JudgeOnline/problem.php?id=2434
題解:
我寫的是離線做法,不知道有沒有在線做法。
轉化一波題意,\(x\)在AC自動機上代表的字符串在\(y\)代表的字符串中出現的次數等于\(x\)在fail樹的子樹內有多少個點是\(y\)點Trie樹上的祖先。
然后不難得到做法: 將詢問離線按照\(y\)在AC自動機上的id排序(一個正常的構建Trie的方式建出來應該就滿足節點的編號是它的Trie樹DFS序).
在Trie樹上DFS, 同時回答詢問, 用樹狀數組維護即可
代碼
#include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std;const int N = 1e5; const int S = 26; struct Edge {int v,nxt; } e[(N<<1)+3]; struct Query {int x,y,id;bool operator <(const Query &arg) const{return y<arg.y;} } qr[N+3]; int fe[N+3]; int dfn[N+3]; int fa[N+3]; int son[N+3][S+3]; int fail[N+3]; char str[N+3]; int stk[N+3]; int id[N+3]; int que[N+3]; int bit[N+3]; int ord[N+3]; int ans[N+3]; int sz[N+3]; int n,q,siz,m,cnt,en;void addval(int lrb,int val) {while(lrb<=cnt){bit[lrb] += val;lrb += (lrb&(-lrb));} }int querysum(int rb) {int ret = 0;while(rb){ret += bit[rb];rb -= (rb&(-rb));}return ret; }void addedge(int u,int v) {en++; e[en].v = v;e[en].nxt = fe[u]; fe[u] = en; }void buildTrie() {int u = 0,tp = 0; stk[tp] = 0;for(int i=1; i<=n; i++){if(str[i]=='B'){stk[tp] = 0; tp--;u = stk[tp];}else if(str[i]=='P'){m++; id[m] = u;}else{str[i]-=96;if(!son[u][str[i]]) {siz++; son[u][str[i]] = siz;}u = son[u][str[i]];tp++; stk[tp] = u;}} }void buildACA() {int head = 1,tail = 0;for(int i=1; i<=S; i++) {if(son[0][i]) {tail++; que[tail] = son[0][i];} fail[son[0][i]] = 0;}while(head<=tail){int u = que[head]; head++;addedge(fail[u],u); addedge(u,fail[u]);for(int i=1; i<=S; i++){if(son[u][i]) {fail[son[u][i]] = son[fail[u]][i]; tail++; que[tail] = son[u][i];}else {son[u][i] = son[fail[u]][i];}}} }void dfs(int u) {cnt++; dfn[u] = cnt;sz[u] = 1;for(int i=fe[u]; i; i=e[i].nxt){if(e[i].v==fa[u]) continue;fa[e[i].v] = u;dfs(e[i].v);sz[u] += sz[e[i].v];} }int main() {scanf("%s",str+1); n = strlen(str+1);scanf("%d",&q);buildTrie();buildACA();for(int i=1; i<=q; i++){int x,y; scanf("%d%d",&x,&y);qr[i].x = id[x]; qr[i].y = id[y]; qr[i].id = i;}dfs(0);sort(qr+1,qr+q+1);int u = 0,tp = 0,j = 0; stk[tp] = 0; addval(dfn[u],0);for(int i=1; i<=n; i++){if(str[i]=='B'){addval(dfn[u],-1);stk[tp] = 0; tp--;u = stk[tp];}else if(str[i]=='P'){while(j<q && qr[j+1].y==u){j++;ans[qr[j].id] = querysum(dfn[qr[j].x]+sz[qr[j].x]-1)-querysum(dfn[qr[j].x]-1);}}else{u = son[u][str[i]];tp++; stk[tp] = u;addval(dfn[u],1);}}for(int i=1; i<=q; i++){printf("%d\n",ans[i]);}return 0; }總結
以上是生活随笔為你收集整理的BZOJ 2434 Luogu P2414 [NOI2011]阿狸的打字机 (AC自动机、树状数组)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ 2754 [SCOI2012]
- 下一篇: BZOJ 4044 Luogu P476