BZOJ 2434 ali的打字机 发表于 2017-01-09 | 更新于 2018-06-17 LinkSolutionFail树。子树和。经典思路。 TipsAC自动机好像用到了不少记录某个字符匹配到哪个状态的情况啊。一开始太naive,直接暴力插入暴力查询,时间爆炸了。 Code123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172//Code by Lucida#include<bits/stdc++.h>#define get(x) scanf("%d",&x)//#define debug(x) std::cout<<#x<<'='<<x<<std::endltemplate <class T> inline bool chkmx(T &a,const T &b){return a<b?a=b,1:0;}template <class T> inline bool chkmn(T &a,const T &b){return a>b?a=b,1:0;}const int MAXN=1e5+10;namespace AC{ const int SIGMA=26; const int SIZE=MAXN<<3; struct Node { Node *son[SIGMA],*fail,*last;int cnt; Node *&next(char c){return son[c-'a'];} int num(); }*ME=(Node*)malloc(SIZE*sizeof(Node)),*HEAD=ME; int Node::num(){return this-HEAD+1;} Node *newNode() { static Node *cur; cur=ME++;cur->fail=cur->last=0;cur->cnt=0; memset(cur->son,0,sizeof(cur->son));return cur; } struct AC { Node *root; AC(){root=newNode();} void Build() { static Node *Q[SIZE];static int he,ta; he=1,ta=0;root->last=0;root->cnt=0;root->fail=root; for(char c='a';c<='z';++c) if(!root->next(c)) root->next(c)=root; else { root->next(c)->fail=root; root->next(c)->last=0; Q[++ta]=root->next(c); } while(he<=ta) { Node *cur=Q[he++]; for(char c='a';c<='z';++c) { Node *&son=cur->next(c); if(!son) son=cur->fail->next(c); else { son->fail=cur->fail->next(c); son->last=son->fail->cnt?son->fail:son->fail->last; Q[++ta]=son; } } } } }mata;}using namespace AC;struct Edge{int to,pre;}e[MAXN<<1];int ec,id[MAXN];void Adde(int f,int t){ e[++ec].to=t;e[ec].pre=id[f];id[f]=ec; e[++ec].to=f;e[ec].pre=id[t];id[t]=ec;}void BuildTree(){ for(Node *ptr=HEAD;ptr!=ME;++ptr) Adde(ptr->num(),ptr->fail->num());}int dfs[SIZE],dc,li[SIZE],ro[SIZE];void DFS(int pos){ dfs[li[pos]=++dc]=pos; for(int i=id[pos];i;i=e[i].pre) { int u=e[i].to; if(li[u]) continue; DFS(u); } ro[pos]=dc;}struct Bit{ int n,a[SIZE]; #define lowbit(x) (x & -x) int Sum(int pos) { int res=0; for(;pos;pos-=lowbit(pos)) res+=a[pos]; return res; } void Add(int pos,int v) { if(!pos) return; for(;pos<=n;pos+=lowbit(pos)) a[pos]+=v; } int Sum(int l,int r){return Sum(r)-Sum(l-1);} #undef lowbit}bit;struct List{int to,id,pre;}q[MAXN];int qc,head[MAXN],ANS[MAXN];void Addq(int f,int t,int id){q[++qc].to=t;q[qc].id=id;q[qc].pre=head[f];head[f]=qc;}int main(){ freopen("input","r",stdin); static char str[MAXN],*cptr=str,now[MAXN],*nptr=now; static Node *ref[MAXN],*state[MAXN];int sc=0; scanf("%s",str); state[0]=mata.root; for(cptr=str;*cptr;++cptr) { Node *cur=state[nptr-now]; if(*cptr=='B') *nptr--=0;//--nptr; else if(*cptr=='P') ref[++sc]=cur; else { *++nptr=*cptr; if(!cur->next(*nptr)) cur->next(*nptr)=newNode(); cur=cur->next(*nptr); state[nptr-now]=cur; } } mata.Build(); BuildTree(); int root=mata.root->num(); DFS(root);bit.n=dc; int m;get(m); for(int i=1;i<=m;i++) { int x,y;get(x),get(y); Addq(y,x,i); } while(nptr!=now) *nptr--=0; for(sc=0,cptr=str;*cptr;++cptr) { Node *cur=state[nptr-now]; if(*cptr=='B') { *nptr--=0; bit.Add(li[cur->num()],-1); } else if(*cptr=='P') { ++sc; for(int i=head[sc];i;i=q[i].pre) { int u=ref[q[i].to]->num(); ANS[q[i].id]=bit.Sum(li[u],ro[u]); } } else { *++nptr=*cptr; state[nptr-now]=cur=cur->next(*nptr); bit.Add(li[cur->num()],1); } } for(int i=1;i<=m;i++) printf("%d\n",ANS[i]); return 0;}/* AC Record(Bugs) * * WA sizeof array too small (turned out to be no problem) * WA printf %s error ---> printfing char*,deleted words must be cleared * MLE using list to contain,maybe n^2 * WA in the for-loop below nptr wasn't reset * AND the characters in now[]wasn't cleared same as above * TLE Forever loop-->not forever * the Inserting is too slow..too simple.. * the Matching is too slow..too simple.. * * * * * * * * * */