【HDU】4117 GRE Words AC自动机+线段树优化DP

传送门:【HDU】4117 GRE Words


题目分析:水不了啊狸的打字机就来水这题了= =。。。

首先建立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 ;
}


你可能感兴趣的:(HDU)