瑶瑶想找回文串
Time Limit: 20000/10000MS (Java/Others)
Memory Limit: 256000/128000KB (Java/Others)
Problem Description
刚学完后缀数组求回文串的瑶瑶(tsyao)想到了另一个问题:如果能够对字符串做一些修改,怎么在每次询问时知道以某个字符为中心的最长回文串长度呢?因为瑶瑶整天只知道LOL,当他知道自己省选成绩的时候就天天在LOL,导致现在的她实在是太弱了,根本解决不了这个问题,于是就来找你帮忙,么么哒~你就帮帮她吗
Input
第一行为一个长度不超过100000字符串s作为初始字符串。第二行一个正整数n,表示操作/询问的个数。接下来n行,每行有如下几种可能出现的操作/询问:
Insert a x 在a处字符的后面插入一个字符x
Delete a 把a处字符删除
Update a x 把a处字符改为x
Query a 查询以a为中心的最长回文串长度
Output
对于每个询问,输出得到的最长回文串长度
Sample Input
baaaaab 5 Query 4 Delete 2 Query 3 Delete 4 Query 3
Sample Output
7 3 5
Hint
对于100%的数据 1<=n<=50000,字符串仅包含小写字母,保证操作过程中字符串长度不超过150000 (hint:请各位大胆写)
单组输入,共10组数据。
Source
zslzx
Manager
二分+字符串哈希+splay;
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<ctime>
#include<map>
#include<set>
#include<stack>
#include<list>
#define maxn 200010
#define LL long long
#define u64 unsigned long long
#define yy 133
using namespace std ;
int num[maxn];
u64 bit[maxn];
struct node {
int size ;
int ch[2];
int pra;
u64 lsum,rsum,val;
void init( int tt ) {
ch[0] = ch[1] = 0;
size = 1;
lsum = rsum = val = tt ;
}
} tree[maxn];
int len;
int root;
char a[maxn];
int n, m;
int getSize(int x) {
if (x) return tree[x].size;
return 0;
}
u64 getlsum( int x )
{
if(x) return tree[x].lsum ;
return 0 ;
}
u64 getrsum( int x )
{
if(x) return tree[x].rsum ;
return 0 ;
}
void update(int x) {
tree[x].size = 1 + getSize(tree[x].ch[0]) + getSize(tree[x].ch[1]);
tree[x].lsum = tree[x].val*bit[getSize(tree[x].ch[0])] + getlsum(tree[x].ch[0])
+getlsum(tree[x].ch[1])*bit[getSize(tree[x].ch[0])+1] ;
tree[x].rsum = tree[x].val*bit[getSize(tree[x].ch[1])] + getrsum(tree[x].ch[1])
+getrsum(tree[x].ch[0])*bit[getSize(tree[x].ch[1])+1] ;
}
void build( int &x , int s , int e , int f )
{
if(s>e) return ;
int mid = (s+e)>>1 ;
x = ++len ;
tree[x].pra = f ;
tree[x].init(num[mid]) ;
build(tree[x].ch[0],s,mid-1,x) ;
build(tree[x].ch[1],mid+1,e,x) ;
update(x) ;
}
void init()
{
int i , k , l ;
len = 0 ;
tree[0].pra = -1 ;
tree[0].init(-1) ;
for( i = 1 ; i <= n ;i++){
num[i] = a[i-1]-'a'+1;
}
num[0] = num[n+1] = -1 ;
build( tree[0].ch[1] , 0 , n+1 , 0 ) ;
}
void rotate(int x , int d )
{
int p = tree[x].pra ;
tree[p].ch[d] = tree[x].ch[d^1] ;
tree[tree[x].ch[d^1]].pra = p ;
tree[x].ch[d^1] = p ;
int g = tree[p].pra ;
tree[p].pra = x ;
if( g != -1 )
tree[g].ch[p == tree[g].ch[1]] = x ;
tree[x].pra = g ;
//更新值
tree[x].size = tree[p].size ;
update(p) ;
return ;
}
void splay( int &x , int f )
{
while( tree[x].pra != f )
{
int p = tree[x].pra ;
if(tree[p].pra == f )
{
if( tree[p].ch[0] == x ) rotate(x,0) ;
else rotate(x,1) ;
}
else
{
int g = tree[p].pra ;
if( tree[g].ch[0] == p )
{
if( tree[p].ch[0] == x )
rotate(p,0),rotate(x,0) ;
else rotate(x,1),rotate(x,0) ;
}
else{
if( tree[p].ch[1] == x )
rotate(p,1),rotate(x,1) ;
else rotate(x,0),rotate(x,1) ;
}
}
}
update(x) ;
}
void select( int k , int f )
{
int x = tree[0].ch[1] ;
while( k != getSize(tree[x].ch[0])+1)
{
if( k <= getSize(tree[x].ch[0]))
{
x = tree[x].ch[0] ;
}
else
{
k -= 1+getSize(tree[x].ch[0]) ;
x = tree[x].ch[1] ;
}
}
splay(x,f) ;
}
void cut()
{
int a, b , c , i ;
scanf("%d" , &a) ;
b = a ;
select(a,0) ;
root = tree[0].ch[1] ;
select(b+2,root) ;
int tmp = tree[tree[root].ch[1]].ch[0] ;
n-- ;
tree[tree[root].ch[1]].ch[0] = 0 ;
update(tree[root].ch[1]) ;
update(root) ;
}
void replace()
{
int a, b , i ;
char c[2];
scanf("%d%s" , &a,c ) ;
b = a ;
select(a,0) ;
root = tree[0].ch[1] ;
select(b+2,root) ;
int tmp = tree[tree[root].ch[1]].ch[0] ;
tree[tmp].init(c[0]-'a'+1) ;
update(tree[root].ch[1]) ;
update(root) ;
}
void insert()
{
int a, b , i ;
char c[2];
scanf("%d%s" , &a,c ) ;
select(a+1,0) ;
root = tree[0].ch[1] ;
select(a+2,root) ;
n++;
int tmp = ++len ;
tree[tmp].init(c[0]-'a'+1) ;
tree[tree[root].ch[1]].ch[0] = tmp ;
tree[tmp].pra = tree[root].ch[1] ;
update(tree[root].ch[1]) ;
update(root) ;
}
bool check(int k,int mid)
{
select(k-mid,0) ;
root = tree[0].ch[1] ;
select(k+mid+2,root) ;
int tmp = tree[tree[root].ch[1]].ch[0] ;
return tree[tmp].lsum == tree[tmp].rsum ;
}
int main()
{
int i,k ;
int L,R,mid,ans;
u64 u,v;
char str[20] ;
bit[0]=1;
for( i = 1 ; i < maxn-10 ;i++)
bit[i]=bit[i-1]*yy;
while(scanf("%s",a) != EOF)
{
n = strlen(a) ;
init();
scanf("%d",&m) ;
while(m--)
{
scanf("%s",str) ;
if(str[0]=='I')
{
insert();
}
else if(str[0]=='D')
{
cut();
}
else if(str[0]=='U')
{
replace();
}
else{
ans=0;
scanf("%d",&k);
L=0;R=min(k-1,n-k);
while(L<R)
{
mid=(L+R+1)>>1 ;
if(check(k,mid))
{
ans=mid;
L=mid;
}
else R = mid-1;
}
printf("%d\n",ans*2+1);
}
}
}
return 0 ;
}