zoj3533 Gao the String I(splay)

题目链接:zoj3533 Gao the String I

题意:其实就是维护一个数列。有四个操作,reverse和modify就是常见的splay操作,lcp(i,j)操作,表示求后缀i,j的最长公共前缀,palindrome是求整个串的最长回文串。

解题思路:首先我们要搞清楚的是要维护什么,palindrome操作因为只有10个,所以这个是可以暴力做的。那么关键的是怎么求lcp了,没什么好的办法,hash+二分吧,所以这里维护的就是一段区间的hash值了,因为有reverse操作,所以要维护正反两个hash值,reverse的时候,swap之即可。palindrome的话,就是按先序遍历,把字符串读出来,然后用manacher算法搞一遍就ok了(manacher算法,百度之。。有好多文章都写的好详细),不会manacher的话,用后缀数组也可搞,用hash+二分也可搞。总之他只有十个操作,所以暴力之即可。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <math.h>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#define lowbit(x) (x&(-x))
#define ll long long
#define ull unsigned long long
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
#define ls son[0][rt]
#define rs son[1][rt]
#define new_edge(a,b,c) edge[tot].t = b , edge[tot].v = c , edge[tot].next = head[a] , head[a] = tot ++
using namespace std;

const int maxn = 111111 ;
int son[2][maxn] , fa[maxn] , size[maxn] , col[maxn] ;
char s[maxn] ;
ull val[maxn] , sum[maxn] , hash_value[2][maxn] ;
ull x = 127 , p[maxn] ;

void new_node ( ull _val , int rt ) {
	if ( !rt ) return ;
	col[rt] = ls = rs = fa[rt] = sum[rt] = 0 ;
	val[rt] = _val ;
	size[rt] = 1 ;
}

void push_up ( int rt ) {
	size[rt] = size[ls] + size[rs] + 1 ;
	sum[rt] = sum[rs] * p[size[ls]+1] + val[rt] * p[size[ls]] + sum[ls] ;
	hash_value[0][rt] = hash_value[0][rs] * p[size[ls]+1] + val[rt] * p[size[ls]] + hash_value[0][ls] ;
	hash_value[1][rt] = hash_value[1][ls] * p[size[rs]+1] + val[rt] * p[size[rs]] + hash_value[1][rs] ;
}

void reverse ( int rt ) {
	if ( !rt ) return ;
	col[rt] ^= 1 ;
	swap ( ls , rs ) ;
	swap ( hash_value[0][rt] , hash_value[1][rt] ) ;
	sum[rt] = hash_value[0][rt] ;
}

void push_down ( int rt ) {
	if ( col[rt] ) {
		reverse ( ls ) ; reverse ( rs ) ;
		col[rt] = 0 ;
	}
}

void down ( int rt ) {
	if ( fa[rt] ) down ( fa[rt] ) ;
	push_down ( rt ) ;
}

void rot ( int rt ) {
	int y = fa[rt] , z = fa[y] , c = rt == son[0][y] ;
	son[!c][y] = son[c][rt] , fa[son[c][rt]] = y ;
	son[c][rt] = y , fa[y] = rt ;
	fa[rt] = z ;
	son[y==son[1][z]][z] = rt ;
	push_up ( y ) ;
}

void splay ( int rt , int to ) {
	down ( rt ) ;
	while ( fa[rt] != to ) {
		int y = fa[rt] , z = fa[y] ;
		if ( z != to ) rot ( (rt==son[0][y])^(y==son[0][z]) ? rt : y ) ;
		rot ( rt ) ;
	}
	push_up ( rt ) ;
}

int build ( int l , int r ) {
	if ( l > r ) return 0 ;
	int rt = ( l + r ) >> 1 ;
	new_node ( (ull)s[rt-1] , rt ) ;
	ls = build ( l , rt - 1 ) ; fa[ls] = rt ;
	rs = build ( rt + 1 , r ) ; fa[rs] = rt ;
	push_up ( rt ) ;
	return rt ;
}

int cnt ( int rt , int k ) {
	push_down ( rt ) ;
	if ( size[ls] + 1 == k ) return rt ;
	if ( size[ls] >= k ) return cnt ( ls , k ) ;
	return cnt ( rs , k - size[ls] - 1 ) ;
}

int rad[maxn<<2] , s1[maxn<<2] , tot ;

void gao ( int rt ) {
	if ( !rt ) return ;
	push_down ( rt ) ;
	gao ( ls ) ;
	s[tot++] = (int) val[rt] ;
	gao ( rs ) ;
}

int Pal ( int n  , int rt ) {
	int i , j , k , len = 2 ;
	tot = 0 ;
	gao ( rt ) ;
	s1[0] = '$' , s1[1] = '#' ;
	for ( i = 1 ; i <= n ; i ++ ) s1[len++] = (int)s[i] , s1[len++] = '#' ;
	int id = 0 , mx = 0 , ans = 0 ;
	rad[0] = 1 ;
	for ( i = 1 ; i < len ; i ++ ) {
		if ( mx >= i ) rad[i] = min ( rad[2*id-i] , mx - i ) ;
		else rad[i] = 1 ;
		while ( s1[i+rad[i]] == s1[i-rad[i]] ) rad[i] ++ ;
		if ( rad[i] + i - 1 > mx ) mx = rad[i] + i - 1 , id = i ;
		ans = max ( ans , rad[i] - 1 ) ;
	}
	return ans ;
}

ull get ( int l , int r , int &rt ) {
	l -- , r ++ ;
	l = cnt ( rt , l ) ; r = cnt ( rt , r ) ;
	splay ( l , 0 ) ;
	splay ( r , l ) ;
	rt = l ;
	return sum[son[0][r]] ;
}

int Lcp ( int a , int b , int n , int &rt ) {
	a ++ , b ++ ; n ++ ;
	int l = 1 , r = n - max ( a , b ) + 1 ;
	while ( l <= r ) {
		int m = ( l + r ) >> 1 ;
		ull t1 = get ( a , a + m - 1 , rt ) , t2 = get ( b , b + m - 1 , rt ) ;
		if ( t1 == t2 ) l = m + 1 ;
		else r = m - 1 ;
	}
	return r ;
}

int Reverse ( int l , int r , int rt ) {
    l -- , r ++ ;
	l = cnt ( rt , l ) ; r = cnt ( rt , r ) ;
	splay ( l , 0 ) ;
	splay ( r , l ) ;
	reverse ( son[0][r] ) ;
	push_up ( r ) ; push_up ( l ) ;
	return l ;
}

int Modify ( int p , ull _val , int rt ) {
	p ++ ;
	p = cnt ( rt , p ) ;
	splay ( p , 0 ) ;
	val[p] = _val ;
	push_up ( p ) ;
	return p ;
}

int main() {
	int i , j , k , n , m , q ;
	p[0] = 1 ;
	for ( i = 1 ; i < maxn ; i ++ ) p[i] = p[i-1] * x ;
	while ( scanf ( "%s" , s + 1 ) != EOF ) {
		n = strlen ( s + 1 ) ;
		s[0] = s[n+1] = s[n+2] = 0 ;
		int rt = build ( 1 , n + 2 ) ;
		scanf ( "%d" , &m ) ;
		while ( m -- ) {
			char op[22] ;
			int a , b ;
			scanf ( "%s" , op ) ;
			if ( op[0] == 'L' ) {
				scanf ( "%d%d" , &a , &b ) ;
				printf ( "%d\n" , Lcp ( a , b , n , rt ) ) ;
			}
		 	else if ( op[0] == 'P' ) printf ( "%d\n" , Pal ( n , rt ) ) ;
			else if ( op[0] == 'R' ) {
				scanf ( "%d%d" , &a , &b ) ;
				a ++ , b ++ ;
				rt = Reverse ( a , b , rt ) ;
			}
			else {
				scanf ( "%d%s" , &a , op ) ;
				rt = Modify ( a , op[0] , rt ) ;
			}
			tot = 0 ;
		 }
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值