HDU - 4117
构建AC自动机
dp从每一个的子串上转移过来
转移过程中不断匹配,然后统计\(fail\)树上前缀的最大值,这是一个动态的过程
于是我们用树剖线段树动态维护
const int N=2e4+10,SIZE=2.3e5+10;
bool be;
int n,m;
string s[N];
int End[N],val[N];
int trie[SIZE][26],fail[SIZE],cnt;
void clear(){
memset(trie,0,sizeof (int) * (cnt+1)*26);
cnt=0;
}
int Insert(string &s){
int p=0;
rep(i,0,s.size()-1) {
//if(!isalpha(s[i])) while(1);
int x=s[i]-'a';
if(!trie[p][x]) trie[p][x]=++cnt;
p=trie[p][x];
}
return p;
}
int sz[SIZE],son[SIZE],top[SIZE],fa[SIZE];
struct Edge{
int to,nxt;
}e[SIZE];
int head[SIZE],ecnt;
void AddEdge(int u,int v){
e[++ecnt].to=v;
e[ecnt].nxt=head[u];
head[u]=ecnt;
}
void dfs1(int u){
sz[u]=1,son[u]=-1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(!v) continue;
fa[v]=u;
dfs1(v);
sz[u]+=sz[v];
if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v;
}
}
int L[SIZE],R[SIZE],dfn;
//id[SIZE];
void dfs2(int u,int t){
top[u]=t;
L[u]=++dfn;
if(~son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(!v||v==son[u]) continue;
dfs2(v,v);
}
R[u]=dfn;
}
void chk(int &a,int b){ ((a<b)&&(a=b)); }
struct SGT{
int sum[SIZE<<2];
void clear() { memset(sum,0,sizeof sum); }
void Upd(int p,int l,int r,int x,int y){
chk(sum[p],y);
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) Upd(p<<1,l,mid,x,y);
else Upd(p<<1|1,mid+1,r,x,y);
}
int Que(int p,int l,int r,int ql,int qr){
if(l==ql&&r==qr) return sum[p];
int mid=(l+r)>>1;
if(qr<=mid) return Que(p<<1,l,mid,ql,qr);
else if(ql>mid) return Que(p<<1|1,mid+1,r,ql,qr);
else return max(Que(p<<1,l,mid,ql,mid),Que(p<<1|1,mid+1,r,mid+1,qr));
}
}tr;
void Build(){
static queue <int> que;
dfn=0;
memset(head,0,sizeof head);ecnt=0;
rep(i,0,25) if(trie[0][i]) {
que.push(trie[0][i]);
fail[trie[0][i]]=0;
}
while(!que.empty()){
int u=que.front(); que.pop();
AddEdge(fail[u],u);
rep(i,0,25) {
int &v=trie[u][i];
if(v) {
que.push(v);
fail[v]=trie[fail[u]][i];
} else v=trie[fail[u]][i];
}
}
fa[0]=-1,dfs1(0);dfs2(0,0);
}
bool ed;
int main(){
//cout<<&ed-&be<<endl;
ios::sync_with_stdio(false);
int T; cin>>T;
rep(kase,1,T) {
clear();
tr.clear();
cin>>n;
rep(i,1,n) {
cin>>s[i]>>val[i];
End[i]=Insert(s[i]);
}
Build();
int ans=0;
rep(i,1,n) {
int res=0,p=0;
rep(j,0,s[i].size()-1) {
p=trie[p][s[i][j]-'a'];
int x=p;
while(~x) {
chk(res,tr.Que(1,1,dfn,L[top[x]],L[x]));
x=fa[top[x]];
}
}
chk(res,res+val[i]);
tr.Upd(1,1,dfn,L[End[i]],res);
chk(ans,res);
string t;swap(t,s[i]);
}
printf("Case #%d: %d\n",kase,ans);
}
}