HDU 5069 Harry And Biological Teacher(AC自動機+線段樹)
阿新 • • 發佈:2019-01-06
題意
給定 \(n\) 個字串,\(m\) 個詢問,每次詢問 \(a\) 字串的字尾和 \(b\) 字串的字首最多能匹配多長。
\(1\leq n,m \leq 10^5\)
思路
多串匹配,考慮 \(\text{AC}\)自動機,對 \(n\) 個串建自動機,觀察這個結構,不難發現 \(Trie\) 樹的結構和字首有關,\(fail\) 樹的結構和字尾有關。
考慮離線,對於每個 \(b\) ,儲存它對應的 \(a\) ,我們通過在自動機上掃 \(b\) 來回答。由於掃到某節點 \(u\) ,在 \(fail\) 樹上 \(u\) 的子節點都能得到 \(u\) 在 \(Trie\) 樹上深度的貢獻,最後對每一個 \(a\)
\(\text{AC}\)自動機上有 \(Trie,fail\) 兩棵樹,分別包含前後綴的資訊,這類問題可以通過 \(\text{AC}\)自動機,轉化為樹上問題。
程式碼
#include<bits/stdc++.h> #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i) #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i) #define x first #define y second typedef long long LL; using namespace std; typedef pair<int,int> pii; const int N=1e5+5; const int NN=N*22; int c_d[256]; template<const int maxn,const int maxm>struct Linked_list { int head[maxn],to[maxm],nxt[maxm],tot; Linked_list(){clear();} void clear(){memset(head,-1,sizeof(head));tot=0;} void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;} #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i]) }; struct SegmentTree { int lson[NN],rson[NN],tag[NN]; int rt,tot; void build() { tag[0]=lson[0]=rson[0]=0; rt=tot=0; } void create(int &k) { if(!k) { k=++tot; tag[k]=lson[k]=rson[k]=0; } } void update(int &k,int L,int R,int val,int l,int r) { create(k); if(L<=l&&r<=R){tag[k]=max(tag[k],val);return;} int mid=(l+r)>>1; if(L<=mid)update(lson[k],L,R,val,l,mid); if(R>mid)update(rson[k],L,R,val,mid+1,r); } int query(int k,int x,int l,int r) { if(l==r)return tag[k]; int mid=(l+r)>>1; if(x<=mid)return max(query(lson[k],x,l,mid),tag[k]); else return max(query(rson[k],x,mid+1,r),tag[k]); } }ST; Linked_list<N,N>G; int L[N],R[N],ord; int ch[N][4],f[N],dep[N]; string P[N]; int rt,tot; vector<pii>Qry[N];int Ans[N]; char str[N]; int idx[N]; int n,q; void build(){rt=tot=0;} void create(int &k) { if(!k) { k=++tot; FOR(i,0,3)ch[k][i]=0; } } void insert(int &k,string &str,int id) { create(k); int now=k;dep[now]=0; FOR(i,0,str.length()-1) { create(ch[now][c_d[(int)str[i]]]); now=ch[now][c_d[(int)str[i]]]; dep[now]=i+1; } idx[id]=now; } void get_fail() { queue<int>Q; while(!Q.empty())Q.pop(); f[rt]=rt; FOR(i,0,3) { if(ch[rt][i])f[ch[rt][i]]=rt,Q.push(ch[rt][i]); else ch[rt][i]=rt; } while(!Q.empty()) { int u=Q.front();Q.pop(); FOR(i,0,3) { if(ch[u][i])f[ch[u][i]]=ch[f[u]][i],Q.push(ch[u][i]); else ch[u][i]=ch[f[u]][i]; } } } void dfs_fail(int u) { L[u]=++ord; EOR(i,G,u)dfs_fail(G.to[i]); R[u]=ord; } void query(int k,string &str,vector<pii>&vec) { ST.build(); int now=k; ST.update(ST.rt,L[now],R[now],dep[now],1,tot); FOR(i,0,str.length()-1) { now=ch[now][c_d[(int)str[i]]]; ST.update(ST.rt,L[now],R[now],dep[now],1,tot); } FOR(i,0,(int)vec.size()-1)Ans[vec[i].y]=ST.query(ST.rt,vec[i].x,1,tot); } int main() { c_d[(int)'A']=0,c_d[(int)'C']=1,c_d[(int)'G']=2,c_d[(int)'T']=3; while(~scanf("%d%d",&n,&q)) { G.clear(),build(); FOR(i,1,n)Qry[i].clear(); FOR(i,1,n) { cin>>P[i]; insert(rt,P[i],i); } get_fail(); FOR(i,1,tot)if(f[i]!=i)G.add(f[i],i); ord=0;dfs_fail(rt); FOR(i,1,q) { int a,b; scanf("%d%d",&a,&b); Qry[b].push_back(pii(L[idx[a]],i)); } FOR(i,1,n)query(rt,P[i],Qry[i]); FOR(i,1,q)printf("%d\n",Ans[i]); } return 0; }