题目分析:水不了啊狸的打字机就来水这题了= =。。。
首先建立ac自动机,然后用fail指针的反向关系建边,构造fail指针树。fail指针树中每个结点u表示的串都是其子节点v的后缀(同时该后缀是所有串中最长的)。对fail指针树dfs一次得到时间戳,当要求以串i结尾的最大价值,首先我们需要知道以串i的子串j结尾的最大价值val。因为在树中我们有关系如上所述,所以我们可以对i串的每个字符xi(对应树上一个结点)找到其在树上的价值最大的后缀,然后取最大加上串i本身的价值,即要求的val。然后我们对i的子树【in[i] , ou[i]】更新,即用val更新区间【in[i] , ou[i]】。查询的时候便是单点查询,查询in[xi](xi为属于串i的每个字符)上的最大值。
我语文体育老师教的。
代码如下:
#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#pragma comment(linker, "/STACK:16777216")
#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define root 1 , 1 , ac.cur
#define mid ( ( l + r ) >> 1 )
const int MAXN = 300005 ;
const int MAXE = 1000005 ;
const int INF = 0x3f3f3f3f ;
struct ac_automaton {
int next[MAXN][26] ;
int fail[MAXN] ;
int ac_root ;
int cur ;
int Q[MAXN] , head , tail ;
int newnode () {
rep ( i , 0 , 26 ) next[cur][i] = -1 ;
return cur ++ ;
}
void clear () {
cur = 0 ;
ac_root = newnode () ;
}
inline int encode ( char c ) {
return c - 'a' ;
}
void insert ( char* , int ) ;
void build () {
head = tail = 0 ;
fail[ac_root] = ac_root ;
rep ( i , 0 , 26 ) {
if ( ~next[ac_root][i] ) {
fail[next[ac_root][i]] = ac_root ;
Q[tail ++] = next[ac_root][i] ;
} else next[ac_root][i] = ac_root ;
}
while ( head != tail ) {
int now = Q[head ++] ;
rep ( i , 0 , 26 ) {
if ( ~next[now][i] ) {
fail[next[now][i]] = next[fail[now]][i] ;
Q[tail ++] = next[now][i] ;
} else next[now][i] = next[fail[now]][i] ;
}
}
}
} ;
struct Edge {
int v , n ;
Edge () {}
Edge ( int v , int n ) : v ( v ) , n ( n ) {}
} ;
ac_automaton ac ;
Edge E[MAXE] ;
int lazy[MAXN << 2] ;
int maxv[MAXN << 2] ;
int H[MAXN] , cntE ;
int N[MAXN] , cntN ;
int d[MAXN] ;
int word[MAXN] ;
int val[MAXN] ;
int in[MAXN] , ou[MAXN] , dfs_clock ;
char buf[MAXN] ;
int n ;
void clear () {
cntE = 0 ;
dfs_clock = 0 ;
clr ( N , -1 ) ;
clr ( H , -1 ) ;
clr ( lazy , 0 ) ;
clr ( maxv , 0 ) ;
}
void addedge ( int u , int v , int H[] ) {
E[cntE] = Edge ( v , H[u] ) ;
H[u] = cntE ++ ;
}
void ac_automaton :: insert ( char buf[] , int idx ) {
int now = ac_root ;
for ( int i = 0 ; buf[i] ; ++ i ) {
int index = encode ( buf[i] ) ;
if ( next[now][index] == -1 ) next[now][index] = newnode () ;
now = next[now][index] ;
addedge ( idx , now , N ) ;
}
word[idx] = now ;
}
void dfs ( int u ) {
in[u] = ++ dfs_clock ;
for ( int i = H[u] ; ~i ; i = E[i].n ) dfs ( E[i].v ) ;
ou[u] = dfs_clock ;
}
void push_down ( int o ) {
if ( lazy[o] ) {
lazy[ls] = max ( lazy[ls] , lazy[o] ) ;
lazy[rs] = max ( lazy[rs] , lazy[o] ) ;
maxv[ls] = max ( maxv[ls] , lazy[o] ) ;
maxv[rs] = max ( maxv[rs] , lazy[o] ) ;
lazy[o] = 0 ;
}
}
void push_up ( int o ) {
maxv[o] = max ( maxv[ls] , maxv[rs] ) ;
}
void update ( int L , int R , int v , int o , int l , int r ) {
if ( l == r ) {
lazy[o] = max ( lazy[o] , v ) ;
maxv[o] = max ( maxv[o] , v ) ;
return ;
}
push_down ( o ) ;
int m = mid ;
if ( L <= m ) update ( L , R , v , lson ) ;
if ( m < R ) update ( L , R , v , rson ) ;
push_up ( o ) ;
}
int query ( int x , int o , int l , int r ) {
if ( l == r ) return maxv[o] ;
push_down ( o ) ;
int m = mid ;
if ( x <= m ) return query ( x , lson ) ;
else return query ( x , rson ) ;
}
void solve () {
int x ;
clear () ;
ac.clear () ;
scanf ( "%d" , &n ) ;
For ( i , 1 , n ) {
scanf ( "%s%d" , buf , &val[i] ) ;
ac.insert ( buf , i ) ;
}
ac.build () ;
rep ( i , 1 , ac.cur ) addedge ( ac.fail[i] , i , H ) ;
dfs ( ac.ac_root ) ;
int ans = 0 ;
For ( u , 1 , n ) {
if ( val[u] < 0 ) continue ;
int tmp = 0 ;
for ( int i = N[u] ; ~i ; i = E[i].n ) {
int v = E[i].v ;
tmp = max ( tmp , query ( in[v] , root ) ) ;
}
ans = max ( tmp + val[u] , ans ) ;
update ( in[word[u]] , ou[word[u]] , tmp + val[u] , root ) ;
}
printf ( "%d\n" , ans ) ;
}
int main () {
int T , cas = 0 ;
scanf ( "%d" , &T ) ;
while ( T -- ) {
printf ( "Case #%d: " , ++ cas ) ;
solve () ;
}
return 0 ;
}