"Yali Camp 2017 Day7" the similarity of things (suffix automata + LCT + tree array)

description

Click to view topic content

solution

Step1
Build SAM without brain
The longest common suffix of the two prefixes of S A M isparent − tree parent-treeparentlca 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 parentThe 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+1nx+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;
}

Guess you like

Origin blog.csdn.net/Emm_Titan/article/details/113893742