description
solution
Step1
Build SAM without brain
The longest common suffix of the two prefixes of S A M isparent − tree parent-treeparent−lca lcaat two points on t r e el c a , the definition is obvious
Step2
Offline inquiry, sort by the right endpoint from small to large
Step3
Every time a letter is added, ta tata在 p a r e n t − t r e e parent-tree parent−The path to the root node on t r e e is marked withta taThe tag of t a
If you encounter a previously marked tag, it means that the node is thelca lca ofthe old tag and the new tag.l c a
Greedy to overwrite the mark to a larger value
Step4 The subscript of the
tree array statistics
is the left end point. Each time the query subscript is greater than or equal to the maximum depth of
the left end point of the query , each time an old mark is encountered in the process of running to the root, the answer is updated on the tree array and given to the The node is marked with a new label,
but the tree array is used to calculate the prefix sum, so there is an n − x + 1 n-x+1n−x+1 small conversion
Step5
The process of running to the root node is LCT LCTLCT的 a c c e s s access a c c e s s operation
code
#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define maxn 200005
struct node {
int f, val, tag;
int son[2];
}tree[maxn];
struct SAM {
int fa, len;
int son[2];
}t[maxn];
vector < pair < int, int > > G[maxn];
int last = 1, cnt = 1, n, m;
char s[maxn];
int ans[maxn], maxx[maxn], num[maxn], st[maxn];
int lowbit( int x ) {
return x & ( -x );
}
void modify( int x, int val ) {
for( int i = n - x + 1;i <= n;i += lowbit( i ) )
maxx[i] = max( maxx[i], val );
}
int query( int x ) {
int ans = 0;
for( int i = n - x + 1;i;i -= lowbit( i ) )
ans = max( ans, maxx[i] );
return ans;
}
void insert( int id, int x ) {
int pre = last, now = last = ++ cnt;
num[id] = cnt;
t[now].len = t[pre].len + 1;
while( pre && ! t[pre].son[x] ) t[pre].son[x] = now, pre = t[pre].fa;
if( ! pre ) t[now].fa = 1;
else {
int u = t[pre].son[x];
if( t[pre].len + 1 == t[u].len ) t[now].fa = u;
else {
int v = ++ cnt;
t[v] = t[u];
t[v].len = t[pre].len + 1;
t[u].fa = t[now].fa = v;
while( pre && t[pre].son[x] == u ) t[pre].son[x] = v, pre = t[pre].fa;
}
}
}
bool isroot( int x ) {
return tree[tree[x].f].son[0] == x || tree[tree[x].f].son[1] == x;
}
void rotate( int x ) {
int fa = tree[x].f, Gfa = tree[fa].f;
int k = tree[fa].son[1] == x;
if( isroot( fa ) )
tree[Gfa].son[tree[Gfa].son[1] == fa] = x;
tree[x].f = Gfa;
if( tree[x].son[k ^ 1] )
tree[tree[x].son[k ^ 1]].f = fa;
tree[fa].son[k] = tree[x].son[k ^ 1];
tree[x].son[k ^ 1] = fa;
tree[fa].f = x;
}
void change( int x, int val ) {
tree[x].val = tree[x].tag = val;
}
void pushdown( int x ) {
if( ! tree[x].tag ) return;
if( tree[x].son[0] ) change( tree[x].son[0], tree[x].tag );
if( tree[x].son[1] ) change( tree[x].son[1], tree[x].tag );
tree[x].tag = 0;
}
void splay( int x ) {
int Top = 0, y = x;
st[++ Top] = y;
while( isroot( y ) ) st[++ Top] = y = tree[y].f;
while( Top ) pushdown( st[Top --] );
while( isroot( x ) ) {
int fa = tree[x].f, Gfa = tree[fa].f;
if( isroot( fa ) )
( ( tree[Gfa].son[0] == fa ) ^ ( tree[fa].son[0] == x ) ) ? rotate( x ) : rotate( fa );
rotate( x );
}
}
void access( int x, int val ) {
int son;
for( son = 0;x;son = x, x = tree[x].f ) {
splay( x );
modify( tree[x].val, t[x].len );
tree[x].son[1] = son;
}
tree[son].tag = tree[son].val = val;
}
int main() {
scanf( "%d %d %s", &n, &m, s + 1 );
for( int i = 1;i <= n;i ++ ) //树状数组下标必须从1开始
insert( i, s[i] - '0' );
for( int i = 1, l, r;i <= m;i ++ ) {
scanf( "%d %d", &l, &r );
G[r].push_back( make_pair( l, i ) );
}
for( int i = 1;i <= cnt;i ++ ) tree[i].f = t[i].fa;
for( int i = 1;i <= n;i ++ ) {
access( num[i], i );
for( int j = 0;j < G[i].size();j ++ )
ans[G[i][j].second] = query( G[i][j].first );
}
for( int i = 1;i <= m;i ++ )
printf( "%d\n", ans[i] );
return 0;
}