Description
给出一个字符串和多组询问,每次询问一个区间内不同位置的回文串个数。
Solution
这里不是询问本质不同的回文串个数,不能用莫队+回文树。
考虑偶回文串较难处理,先在字符中间插入分隔符,变成长度为
2n+1
2
n
+
1
的串,用manacher处理得到以
i
i
为中心长度大于1的回文串个数,考虑原来的询问
[l,r]
[
l
,
r
]
,变成了新串上的
[2l−1,2r+1]
[
2
l
−
1
,
2
r
+
1
]
,设
L=2l−1
L
=
2
l
−
1
,
R=2r+1
R
=
2
r
+
1
,观察一下发现区间答案为:
设 mid=L+R2 m i d = L + R 2
当 i>mid i > m i d 时( i<=mid i <= m i d 方法类似),需要求 ∑Ri=mid+1min(pi,R−i) ∑ i = m i d + 1 R m i n ( p i , R − i ) 的值。
将所有询问离线,考虑一个位置 i i 的值在为 pi p i ,其余情况则时 R−i R − i (记这种情况为特殊位置)。 R R 端点右移,遇到询问时统计一下特殊位置的个数与特殊位置上的的和就可以计算出局部答案。
至于 i<=mid i <= m i d ,把字符串倒过来再做一遍即可。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=3e5+10;
int f[N];
char s[N],a[N];
int tot=0;
void manacher(){
int lm=0;
int id,l=tot;
for(int i=1;i<=l;i++){
f[i]=lm>i?min(f[2*id-i],lm-i):1;
while(a[i+f[i]]==a[i-f[i]]) f[i]++;
if(f[i]+i>lm) lm=f[i]+i,id=i;
}
fo(i,1,l) f[i]--;
}
struct node{
int l,r,mid,p;
}b[N];
int n,m;
ll an[N],cd[N];
bool cmp(node x,node y){
return x.r<y.r;
}
struct tree{
ll t,s,sf;
}tr[N<<1];
void update(int v){
tr[v].t=tr[v<<1].t+tr[(v<<1)+1].t;
tr[v].s=tr[v<<1].s+tr[(v<<1)+1].s;
tr[v].sf=tr[v<<1].sf+tr[(v<<1)+1].sf;
}
void build(int v,int l,int r){
if(l==r){
tr[v].s=l,tr[v].t=1,tr[v].sf=0;
return;
}
int mid=(l+r)>>1;
build(v<<1,l,mid),build((v<<1)+1,mid+1,r);
update(v);
}
void modify(int v,int l,int r,int x){
if(l==r){
tr[v].s=tr[v].t=0,tr[v].sf=f[x];
return;
}
int mid=(l+r)>>1;
x<=mid?modify(v<<1,l,mid,x):modify((v<<1)+1,mid+1,r,x);
update(v);
}
int now;
ll sum(int v,int l,int r,int x,int y){
if(l==x && r==y) return tr[v].sf+(ll)now*tr[v].t-tr[v].s;
int mid=(l+r)>>1;
if(y<=mid) return sum(v<<1,l,mid,x,y);
else if(x>mid) return sum((v<<1)+1,mid+1,r,x,y);
else return sum(v<<1,l,mid,x,mid)+sum((v<<1)+1,mid+1,r,mid+1,y);
}
vector<int> dl[N];
void solve(){
build(1,1,tot);
fo(i,1,tot) dl[i+f[i]].push_back(i);
int p=0;
fo(i,1,tot){
now=i;
int o=dl[i].size();
fo(j,0,o-1) modify(1,1,tot,dl[i][j]);
while(p<m && b[p+1].r==i){
p++;
an[b[p].p]+=sum(1,1,tot,b[p].mid,b[p].r);
cd[b[p].p]=(b[p].r-b[p].l)/2;
}
}
fo(i,1,tot) dl[i].clear();
}
int main()
{
freopen("gene.in","r",stdin);
freopen("gene.out","w",stdout);
scanf("%d %d",&n,&m);
scanf("%s",s+1);
fo(i,1,n) a[++tot]='#',a[++tot]=s[i];
a[++tot]='#';
a[0]='*';
manacher();
fo(i,1,m){
scanf("%d %d",&b[i].l,&b[i].r),b[i].p=i;
b[i].l=2*b[i].l-1,b[i].r=2*b[i].r+1;
b[i].mid=(b[i].l+b[i].r)/2;
}
sort(b+1,b+m+1,cmp);
solve();
reverse(f+1,f+tot+1);
fo(i,1,m){
int l=b[i].l,r=b[i].r;
b[i].l=tot-r+1,b[i].r=tot-l+1;
b[i].mid=(b[i].l+b[i].r)/2+1;
}
sort(b+1,b+m+1,cmp);
solve();
fo(i,1,m) printf("%lld\n",(an[i]+cd[i])/2);
}