CF163E e-Government(AC自动机+树剖)
给出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]);
}
}
}