链接
题解
挺神的一个题,这个题就是要求这样一个东西:对于一个区间中的每一个回文中心,看一下这个回文中心最多能往两边延伸几格,使得回文串不能延伸到查询区间外面去。然后这个最多延伸的格数就是其对答案的贡献。
会发现,位于左半个区间的回文中心,在延伸的过程中只可能被区间的左边界截断,位于右半个区间的,只可能被区间的右边界截断。
因此我们分开处理
以左半段为例,问题转化成求 ,这个东西直观看上去很不好处理,这个时候就要用到出题人给的神奇做法:
对于每个 ,我给区间 这些位置加一,然后我要求的东西就转化成了区间 的和
太神了,想不到想不到
代码
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 400010
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
struct Manacher
{
int r[maxn], p[maxn], n;
void clear(){cl(r), cl(p);}
void calc(char *s, int N)
{
n=N;
int i, j, mx(0), center;
r[0]=-2;
for(i=1;i<=N;i++)r[2*i]=s[i];
for(i=1;i<=N;i++)r[2*i-1]=-1;
r[2*N+1]=-1;
for(i=1;i<=2*N+1;i++)
{
if(mx>=i)p[i]=min(p[2*center-i],mx-i+1);
else p[i]=1;
while(r[i-p[i]]==r[i+p[i]])p[i]++;
if(i+p[i]-1>mx)
{
mx=i+p[i]-1;
center=i;
}
}
}
}mnc;
char s[maxn];
ll n, id[maxn], l[maxn], r[maxn], ans[maxn], q;
struct SegmentTree
{
ll mn[maxn<<2], mx[maxn<<2], sum[maxn<<2], add[maxn<<2], set[maxn<<2], L[maxn<<2], R[maxn<<2];
void maketag_set(ll o, ll v)
{
add[o]=0;
set[o]=v;
mx[o]=mn[o]=v;
sum[o]=(R[o]-L[o]+1)*v;
}
void maketag_add(ll o, ll v)
{
add[o]+=v;
mx[o]+=v, mn[o]+=v;
sum[o]+=(R[o]-L[o]+1)*v;
}
void pushdown(ll o)
{
if(L[o]==R[o])return;
if(~set[o])
{
maketag_set(o<<1,set[o]);
maketag_set(o<<1|1,set[o]);
set[o]=-1;
}
if(add[o])
{
maketag_add(o<<1,add[o]);
maketag_add(o<<1|1,add[o]);
add[o]=0;
}
}
void pushup(ll o)
{
mx[o]=max(mx[o<<1],mx[o<<1|1]);
mn[o]=min(mn[o<<1],mn[o<<1|1]);
sum[o]=sum[o<<1]+sum[o<<1|1];
}
void build(ll o, ll l, ll r, ll* array=NULL)
{
ll mid(l+r>>1);
L[o]=l, R[o]=r;
add[o]=0;
set[o]=-1;
if(l==r)
{
if(array)mn[o]=mx[o]=sum[o]=array[l];
else mn[o]=mx[o]=sum[o]=0;
return;
}
build(o<<1,l,mid,array);
build(o<<1|1,mid+1,r,array);
pushup(o);
}
void Set(ll o, ll l, ll r, ll v)
{
ll mid(L[o]+R[o]>>1);
if(l<=L[o] and r>=R[o]){maketag_set(o,v);return;}
pushdown(o);
if(l<=mid)Set(o<<1,l,r,v);
if(r>mid)Set(o<<1|1,l,r,v);
pushup(o);
}
void Add(ll o, ll l, ll r, ll v)
{
ll mid(L[o]+R[o]>>1);
if(l<=L[o] and r>=R[o]){maketag_add(o,v);return;}
pushdown(o);
if(l<=mid)Add(o<<1,l,r,v);
if(r>mid)Add(o<<1|1,l,r,v);
pushup(o);
}
ll Sum(ll o, ll l, ll r)
{
pushdown(o);
ll mid(L[o]+R[o]>>1), ans(0);
if(l<=L[o] and r>=R[o])return sum[o];
if(l<=mid)ans+=Sum(o<<1,l,r);
if(r>mid)ans+=Sum(o<<1|1,l,r);
return ans;
}
ll Min(ll o, ll l, ll r)
{
ll mid(L[o]+R[o]>>1), ans(linf);
if(l<=L[o] and r>=R[o])return mn[o];
pushdown(o);
if(l<=mid)ans=min(ans,Min(o<<1,l,r));
if(r>mid)ans=min(ans,Min(o<<1|1,l,r));
return ans;
}
ll Max(ll o, ll l, ll r)
{
ll mid(L[o]+R[o]>>1), ans(-linf);
if(l<=L[o] and r>=R[o])return mx[o];
pushdown(o);
if(l<=mid)ans=max(ans,Max(o<<1,l,r));
if(r>mid)ans=max(ans,Max(o<<1|1,l,r));
return ans;
}
}segtree;
int main()
{
ll i, j;
n=read(), q=read();
scanf("%s",s+1);
mnc.calc(s,n);
// rep(i,1,2*n)printf("p[%d]=%d\n",i,mnc.p[i]);
rep(i,1,q)l[i]=2*read()-1, r[i]=2*read()+1, id[i]=i;
sort(id+1,id+q+1,[&](ll a, ll b){return l[a]+r[a] < l[b]+r[b]; });
segtree.build(1,1,2*n+1);
j=1;
rep(i,1,q)
{
while(j<=(l[id[i]]+r[id[i]]>>1))
{
segtree.Add(1,j-mnc.p[j]+1,j,1);
j++;
}
ans[id[i]] += segtree.Sum(1,l[id[i]],2*n);
}
segtree.build(1,1,2*n+1);
j=2*n+1;
drep(i,q,1)
{
while(j>(l[id[i]]+r[id[i]]>>1))
{
segtree.Add(1,j,j+mnc.p[j]-1,1);
j--;
}
ans[id[i]] += segtree.Sum(1,1,r[id[i]]);
}
rep(i,1,q)
{
ans[i] -= (r[i]+1>>1) - (l[i]>>1);
printf("%lld\n",ans[i]/2);
}
return 0;
}