CF163E e-Government(AC自動機+樹剖)
阿新 • • 發佈:2021-07-13
給出n個字串。每個字串最初的權值都是0。
請你支援以下兩種操作:
1)把第i個字串的權值改成x。
2)給出一個文字串q,詢問所有字串中,是q的子串的最大權值。
做法:
首先對所有字串建立AC自動機。
假設所有字串互不相同。
輸入一個文字串,對於文字串的第i個節點,它到根節點的路徑的權值最大值就是答案
修改+詢問的過程樹鏈剖分維護就行。
對於兩個完全一樣但是編號不同的字串,把相同字串的編號存到一個vector裡。
先標記每個編號屬於哪個vector,然後對該vector用樹狀陣列的形式維護最大值。
修改的時候用vector的最大值去更新節點的權值。
詢問的時候樹鏈剖分處理即可。
#include<bits/stdc++.h> using namespace std; const int maxn=3e5+100; int lowbit (int x) { return x&-x; } int n,m; vector<int> g[maxn]; int son[maxn],id[maxn],fa[maxn],cnt,dep[maxn],sz[maxn],top[maxn],w[maxn],wt[maxn]; int c[maxn<<2]; int tot,tr[maxn][26],fail[maxn]; string s; void up (int i,int l,int r,int p,int v) { if (l==p&&r==p) { c[i]=v; return; } int mid=(l+r)>>1; if (p<=mid) up(i<<1,l,mid,p,v); if (p>mid) up(i<<1|1,mid+1,r,p,v); c[i]=max(c[i<<1],c[i<<1|1]); } int query (int i,int l,int r,int L,int R) { if (l>=L&&r<=R) return c[i]; int mid=(l+r)>>1; int ans=0; if (L<=mid) ans=max(ans,query(i<<1,l,mid,L,R)); if (R>mid) ans=max(ans,query(i<<1|1,mid+1,r,L,R)); return ans; } int qRange (int x,int y) { int ans=0; while (top[x]!=top[y]) { if (dep[top[x]]<dep[top[y]]) swap(x,y); ans=max(ans,query(1,1,cnt,id[top[x]],id[x])); x=fa[top[x]]; } if (dep[x]>dep[y]) swap(x,y); ans=max(ans,query(1,1,cnt,id[x],id[y])); return ans; } void dfs1 (int x,int f,int deep) { dep[x]=deep; fa[x]=f; sz[x]=1; w[x]+=w[f]; int maxson=-1; for (int y:g[x]) { if (y==f) continue; dfs1(y,x,deep+1); sz[x]+=sz[y]; if (sz[y]>maxson) son[x]=y,maxson=sz[y]; } } void dfs2 (int x,int topf) { id[x]=++cnt; top[x]=topf; if (!son[x]) return; dfs2(son[x],topf); for (int y:g[x]) { if (y==fa[x]||y==son[x]) continue; dfs2(y,y); } } vector<int> G[maxn]; vector<int> GC[maxn]; void up1 (int i,int l,int r,int p,int v,int x) { if (l==p&&r==p) { GC[x][i]=v; return; } int mid=(l+r)>>1; if (p<=mid) up1(i<<1,l,mid,p,v,x); if (p>mid) up1(i<<1|1,mid+1,r,p,v,x); GC[x][i]=max(GC[x][i<<1],GC[x][i<<1|1]); } int b[maxn],bb[maxn]; int insert (string s) { int u=0; for (char i:s) { if (!tr[u][i-'a']) tr[u][i-'a']=++tot; u=tr[u][i-'a']; } w[u]++; return u; } void build () { queue<int> q; for (int i=0;i<26;i++) { if (tr[0][i]) { q.push(tr[0][i]); } } while (q.size()) { int u=q.front(); q.pop(); for (int i=0;i<26;i++) { if (tr[u][i]) { fail[tr[u][i]]=tr[fail[u]][i]; q.push(tr[u][i]); } else { tr[u][i]=tr[fail[u]][i]; } } } } int main () { ios::sync_with_stdio(false); cin>>n>>m; for (int i=1;i<=n;i++) { cin>>s; int x=insert(s); bb[i]=x; b[i]=G[x].size(); G[x].push_back(i); } for (int i=1;i<maxn;i++) { while (GC[i].size()<=G[i].size()*5) GC[i].push_back(0); } build(); for (int i=1;i<=tot;i++) { g[fail[i]].push_back(i); } dfs1(0,0,1); dfs2(0,0); while (m--) { string op; cin>>op; if (op=="2") { string t; cin>>t; int u=0; int ans=0; int tt=0; for (char i:t) { u=tr[u][i-'a']; tt+=w[u]; ans=max(ans,qRange(0,u)); } if (!tt) ans=-1; printf("%d\n",ans); } else { int x,xx; cin>>x>>xx; up1(1,0,G[bb[x]].size()-1,b[x],xx,bb[x]); up(1,1,cnt,id[bb[x]],GC[bb[x]][1]); } } }