• [CF666E]Forensic Examination


    题目

      点这里看题目。

    分析

      先对所有的模式串建立广义后缀自动机。
      我们需要求出每个节点的(end-pos)集合,这个可以在 (fail) 树上用线段树合并快速预处理。
      考虑询问。由于字符串的子串就是前缀的后缀,因此我们可以对于每个前缀,处理出它在自动机上的(LCS)对应的节点。那么一个子串在自动机上的位置,一定是对应它的前缀 的对应节点 的 (fail) 祖先。因此我们可以在 (fail) 上面倍增,进而可以在预处理后(O(log_2n))地求出一个子串的对应节点。
      知道了这些,再套用线段树分治得到的信息,我们就可以回答询问了。

    代码

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    
    const int MAXN = 5e5 + 5, MAXM = 5e4 + 5, MAXL = 1e5 + 5, MAXS = MAXL * 100;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0; char s = getchar();int f = 1;
    	while( s < '0' || '9' < s ) { f = 1; if( s == '-' ) f = -1; s = getchar(); }
    	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + s - '0', s = getchar(); }
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ) { putchar( '-' ), x = -x; }
    	if( 9 < x ) { write( x / 10 ); }
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
    	return a > b ? a : b;
    }
    
    struct edge
    {
    	int to, nxt;
    }Graph[MAXL << 1];
    
    struct pii
    {
    	int mx, indx;
    	pii() { mx = 0, indx = 1e6; }
    	pii( const int M, const int I ) { mx = M, indx = I; }
    	bool operator > ( const pii &b ) const { return mx == b.mx ? indx < b.indx : mx > b.mx; }
    };
    
    pii bst[MAXS]; 
    int lch[MAXS], rch[MAXS];
    int ed[MAXN], mxl[MAXN];
    int ch[MAXL][26], fa[MAXL][18], mx[MAXL], rot[MAXL], head[MAXL];
    int N, M, Q, lg2, rt, lst, tot, cnt, siz;
    char S[MAXN], T[MAXL];
    
    void upt( const int x ) { bst[x] = MAX( bst[lch[x]], bst[rch[x]] ); }
    void copy( int a, int b ) { fa[a][0] = fa[b][0], mx[a] = mx[b], memcpy( ch[a], ch[b], sizeof ch[b] ); }
    
    void addEdge( const int from, const int to )
    {
    	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
    	head[from] = cnt;
    }
    
    void expand( const char c )
    {
    	int x = c - 'a';
    	if( ch[lst][x] && mx[ch[lst][x]] == mx[lst] + 1 ) { lst = ch[lst][x]; return ; }
    	int p = lst, cur = ++ tot;
    	mx[cur] = mx[lst] + 1, lst = cur;
    	while( p && ! ch[p][x] ) ch[p][x] = cur, p = fa[p][0];
    	if( ! p ) { fa[cur][0] = rt; return ; }
    	int q = ch[p][x];
    	if( mx[q] == mx[p] + 1 ) { fa[cur][0] = q; return ; }
    	int nq = ++ tot; copy( nq, q );
    	mx[nq] = mx[p] + 1, fa[q][0] = fa[cur][0] = nq;
    	if( mx[p] + 1 == mx[cur] ) lst = nq;
    	while( p && ch[p][x] == q ) ch[p][x] = nq, p = fa[p][0];
    }
    
    void update( int &u, const int l, const int r, const int pos )
    {
    	if( ! u ) u = ++ siz; int mid = l + r >> 1;
    	if( l == r ) { bst[u].mx ++, bst[u].indx = l; return ; }
    	if( pos <= mid ) update( lch[u], l, mid, pos );
    	else update( rch[u], mid + 1, r, pos );
    	upt( u );
    }
    
    pii query( const int u, const int l, const int r, const int segL, const int segR )
    {
    	if( ! u ) return pii();
    	if( segL <= l && r <= segR ) return bst[u];
    	if( l == r ) return pii();
    	int mid = l + r >> 1; pii ret = pii();
    	if( segL <= mid ) ret = MAX( ret, query( lch[u], l, mid, segL, segR ) );
    	if( mid < segR ) ret = MAX( ret, query( rch[u], mid + 1, r, segL, segR ) );
    	return ret;
    }
    
    int merg( int lrt, int rrt, int l, int r )
    {
    	if( ! lrt || ! rrt ) return lrt | rrt;
    	int cur = ++ siz, mid = l + r >> 1;
    	if( l == r )
    	{
    		bst[cur] = bst[lrt], bst[cur].mx += bst[rrt].mx;
    		return cur;
    	}
    	lch[cur] = merg( lch[lrt], lch[rrt], l, mid ); 
    	rch[cur] = merg( rch[lrt], rch[rrt], mid + 1, r );
    	upt( cur );
    	return cur;
    }
    
    void DFS( const int u )
    {
    	for( int i = head[u], v ; i ; i = Graph[i].nxt )
    	{
    		DFS( v = Graph[i].to );
    		rot[u] = merg( rot[u], rot[v], 1, M );
    	}
    }
    
    int main()
    {
    	rt = ++ tot;
    	scanf( "%s", S + 1 ), N = strlen( S + 1 );
    	read( M );
    	for( int i = 1 ; i <= M ; i ++ )
    	{
    		lst = rt, scanf( "%s", T + 1 );
    		for( int j = 1 ; T[j] ; j ++ ) 
    			expand( T[j] ), update( rot[lst], 1, M, i );	
    	}
    	for( int i = 2 ; i <= tot ; i ++ ) addEdge( fa[i][0], i );
    	DFS( rt );
    	lg2 = log2( tot );
    	for( int j = 1 ; j <= lg2 ; j ++ )
    		for( int i = 1 ; i <= tot ; i ++ )
    			fa[i][j] = fa[fa[i][j - 1]][j - 1];
    	int p = rt, len;
    	for( int i = 1, x ; i <= N ; i ++ )
    	{
    		x = S[i] - 'a';
    		while( p && ! ch[p][x] ) p = fa[p][0], len = mx[p];
    		if( ! p ) p = rt, len = 0;
    		else len ++, p = ch[p][x];
    		ed[i] = p, mxl[i] = len;
    	}
    	read( Q );
    	int lef, rig, L, R;
    	while( Q -- )
    	{
    		read( lef ), read( rig ), read( L ), read( R );
    		if( mxl[R] < R - L + 1 ) { printf( "%d 0
    ", lef ); continue; }
    		p = ed[R];
    		for( int j = lg2 ; ~ j ; j -- )
    			if( fa[p][j] && mx[fa[p][j]] >= R - L + 1 )
    				p = fa[p][j];
    		pii ans = query( rot[p], 1, M, lef, rig );
    		if( ans.mx == 0 ) ans.indx = lef;
    		write( ans.indx ), putchar( ' ' ), write( ans.mx ), putchar( '
    ' );
    	}
    	return 0;
    }
    
  • 相关阅读:
    此时的我,就像一个炸药包...
    我焦躁,并不只是心里承受,还是因为我上面担着。
    我们应该顶住压力
    git初识后的一些问题
    我近期应该找个机会休整一下了
    权限管理设计的一些感悟
    一个无用的功能
    关于IE8与FireFox中,button内字体总是有一个不垂直居中的问题
    Android之EditText文本框监听事件
    Android流量统计TrafficStats类的使用
  • 原文地址:https://www.cnblogs.com/crashed/p/12987000.html
Copyright © 2020-2023  润新知