说在前面
me发现me学高级算法都要学傻了
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊.jpg
题目
BZOJ4556传送门
看题可进传送门
解法
懒得写解法了
反正自己没有想出来
想到要reverse字符串,然后要建出后缀自动姬,没了
其实思路和BZOJ2746是差不多的,都利用到了LCA的性质,感觉还是比较经典了
clover_hxy的题解 传送门
下面是自带大长度的代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
char ss[100005] ;
int N , M , SAMid , tp , head[200005] ;
//------------------------------------------------
struct SAM_Node{
int len , id , isMain;
SAM_Node *ch[26] , *par ;
} *SAM_root , *las , w[200005] , *tw = w , *arc[100005] ;
struct Seg_Node{
int siz ;
Seg_Node *ch[2] ;
void update(){
siz = 0 ;
if( ch[0] ) siz += ch[0]->siz ;
if( ch[1] ) siz += ch[1]->siz ;
}
} *root[200005] ;
struct Path{
int pre , to ;
}p[200005] ;
//------------------------------------------------
void new_SAM_Node( SAM_Node *&nd , int len ){
nd = ++tw ;
nd->id = ++SAMid ; nd->len = len ;
}
void new_Seg_Node( Seg_Node *&nd ){
nd = new Seg_Node() ; nd->siz = 0 ;
nd->ch[0] = nd->ch[1] = NULL ;
}
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
}
//------------------------------------------------
void Insert( int id , int ith ){
SAM_Node *nd , *tmp = las ;
new_SAM_Node( nd , tmp->len + 1 ) ;
nd->isMain = ith , arc[ith] = nd ;
for( ; tmp && !tmp->ch[id] ; tmp = tmp->par )
tmp->ch[id] = nd ;
if( !tmp ) nd->par = SAM_root ;
else{
SAM_Node *B = tmp->ch[id] ;
if( B->len == tmp->len + 1 ) nd->par = B ;
else{
SAM_Node *nB ; new_SAM_Node( nB , tmp->len + 1 ) ;
nB->par = B->par ;
B->par = nd->par = nB ;
memcpy( nB->ch , B->ch , sizeof( nB->ch ) ) ;
while( tmp && tmp->ch[id] == B )
tmp->ch[id] = nB , tmp = tmp->par ;
}
} las = nd ;
}
void Insert( Seg_Node *&nd , int lf , int rg , int pos ){
new_Seg_Node( nd ) , nd->siz = 1 ;
if( lf == rg ) return ;
int mid = ( lf + rg ) >> 1 ;
if( pos <= mid ) Insert( nd->ch[0] , lf , mid , pos ) ;
else Insert( nd->ch[1] , mid+1,rg , pos ) ;
}
void Merge( Seg_Node *&x , Seg_Node *y ){
if( !y ) return ;
if( !x ){ x = y ; return ; }
Seg_Node *nd ; new_Seg_Node( nd ) ;
*nd = *x ; x = nd ;
Merge( nd->ch[0] , y->ch[0] ) ;
Merge( nd->ch[1] , y->ch[1] ) ;
nd->update() ;
}
//------------------------------------------------
int fa[18][200005] , mdep , logg ;
void dfs( int u , int dep ){
SAM_Node *nd = &w[u] ;
mdep = max( mdep , dep ) ;
if( nd->isMain ) Insert( root[u] , 1 , SAMid , nd->isMain ) ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
fa[0][v] = u , dfs( v , dep + 1 ) ;
Merge( root[u] , root[v] ) ;
}
}
void preWork(){
for( int i = 2 ; i <= SAMid ; i ++ )
In( w[i].par->id , w[i].id ) ;
dfs( 1 , 1 ) ; fa[0][1] = 1 ;
for( logg = 1 ; 1 << ( logg + 1 ) <= mdep ; logg ++ ) ;
for( int i = 1 ; i <= logg ; i ++ )
for( int j = 1 ; j <= SAMid ; j ++ )
fa[i][j] = fa[i-1][ fa[i-1][j] ] ;
}
//------------------------------------------------
int a , b , c , d ;
bool Query( Seg_Node *nd , int lf , int rg , int L , int R ){
if( !nd ) return false ;
if( L <= lf && rg <= R ) return ( bool )nd->siz ;
int mid = ( lf + rg ) >> 1 ;
if( R <= mid ) return Query( nd->ch[0] , lf , mid , L , R ) ;
if( L > mid ) return Query( nd->ch[1] , mid+1,rg , L , R ) ;
return Query( nd->ch[0] , lf , mid , L , R ) || Query( nd->ch[1] , mid+1,rg , L , R ) ;
}
bool check( int mid ){
int u = arc[c]->id ;
for( int i = logg ; i >= 0 ; i -- )
if( w[ fa[i][u] ].len >= mid ) u = fa[i][u] ;
return Query( root[u] , 1 , SAMid , b + mid - 1 , a ) ;
}
void solve(){
for( int i = 1 ; i <= M ; i ++ ){
scanf( "%d%d%d%d" , &a , &b , &c , &d ) ;
a = N-a+1 , b = N-b+1 , c = N-c+1 , d = N-d+1 ;//rev :: d||||||c b||||||a
int lf = 0 , rg = min( c - d + 1 , a - b + 1 ) , ans ;
while( lf <= rg ){
int mid = ( lf + rg ) >> 1 ;
if( check( mid ) )
ans = mid , lf = mid + 1 ;
else rg = mid - 1 ;
} printf( "%d\n" , ans ) ;
}
}
//------------------------------------------------
int main(){
new_SAM_Node( SAM_root , 0 ) ; las = SAM_root ;
scanf( "%d%d%s" , &N , &M , ss + 1 ) ;
for( int i = N ; i ; i -- ) // 反串
Insert( ss[i] - 'a' , N - i + 1 ) ;
preWork() ; solve() ;
}