Description
给定一个字符串,每次询问lll~rrr间有多少个回文串。
Sample Input
abaa
4
1 2
1 3
1 4
3 4
Sample Output
2
4
6
3
考虑每个回文中心做出的贡献,假设它拓展的最长长度为sss,它的位置为p,当前询问为l,rl,rl,r。
那么他的贡献就是:min(len,r−p+1,p−l+1)min(len,r-p+1,p-l+1)min(len,r−p+1,p−l+1)。
我们考虑把它分成两半,[l,mid][l,mid][l,mid],[mid+1,r][mid+1,r][mid+1,r]。
那么其实只有在中间的部分才会同时受到lll和rrr的限制,特殊处理即可。
对于左边的,式子变成:min(len,p−l+1)min(len,p-l+1)min(len,p−l+1)。即p−len+1>=lp-len+1>=lp−len+1>=l算为lenlenlen的贡献,p−len+1<lp-len+1<lp−len+1<l算为p−l+1p-l+1p−l+1的贡献。
可以考虑用树状数组处理。
#include <ctime>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const ULL P = 131;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
struct hh {
int l, s;
} a[100010];
struct node {
int l, r, id;
} a1[300010], a2[300010]; int tp;
ULL s1[100010], s2[100010], o[100010];
int n, mc1[100010], mc2[100010];
LL s[100010], ans[300010];
int num[100010];
char ss[100010];
int lowbit(int x) {return x & -x;}
void change(int x, int c) {for(int i = x; i <= n; i += lowbit(i)) s[i] += c;}
void cnum(int x, int c) {for(int i = x; i <= n; i += lowbit(i)) num[i] += c;}
LL getsum(int x) {LL sum = 0; for(int i = x; i; i -= lowbit(i)) sum += s[i]; return sum;}
int getn(int x) {int sum = 0; for(int i = x; i; i -= lowbit(i)) sum += num[i]; return sum;}
bool cmp1(node a, node b) {return a.l < b.l;}
bool cmp2(node a, node b) {return a.r > b.r;}
bool cmp3(hh a, hh b) {return a.l - a.s < b.l - b.s;}
bool cmp4(hh a, hh b) {return a.l + a.s > b.l + b.s;}
int main() {
scanf("%s", ss + 1);
n = strlen(ss + 1);
s1[0] = 0; for(int i = 1; i <= n; i++) s1[i] = s1[i - 1] * P + ss[i];
s1[n + 1] = 0; for(int i = n; i >= 1; i--) s2[i] = s2[i + 1] * P + ss[i];
o[0] = 1; for(int i = 1; i <= n; i++) o[i] = o[i - 1] * P;
for(int i = 1; i <= n; i++) {
int l = 1, r = _min(i, n - i + 1), ans = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s1[i + mid - 1] - s1[i - 1] * o[mid] == s2[i - mid + 1] - s2[i + 1] * o[mid]) l = mid + 1, ans = mid;
else r = mid - 1;
} mc1[i] = ans;
if(i == n) continue;
l = 1, r = _min(i, n - i + 1), ans = 0;
while(l <= r) {
int mid = (l + r) / 2;
if(s1[i + mid] - s1[i] * o[mid] == s2[i - mid + 1] - s2[i + 1] * o[mid]) l = mid + 1, ans = mid;
else r = mid - 1;
} mc2[i] = ans;
}
int m = read();
for(int i = 1; i <= m; i++) {
int l = read(), r = read();
if(l == r) {ans[i] = 1; continue;}
if((l + r) & 1) {
int mid = (l + r) / 2;
ans[i] += _min(mc2[mid], mid - l + 1);
a1[++tp].l = l, a1[tp].r = mid, a1[tp].id = i;
a2[tp].l = mid + 1, a2[tp].r = r, a2[tp].id = i;
} else {
int mid = (l + r) / 2;
ans[i] += _min(mc1[mid], r - mid + 1);
ans[i] += _min(mc2[mid - 1], mid - l) + _min(mc2[mid], r - mid);
a1[++tp].l = l, a1[tp].r = mid - 1, a1[tp].id = i;
a2[tp].l = mid + 1, a2[tp].r = r, a2[tp].id = i;
}
} sort(a1 + 1, a1 + tp + 1, cmp1), sort(a2 + 1, a2 + tp + 1, cmp2);
for(int i = 1; i <= n; i++) a[i].l = i, a[i].s = mc1[i];
sort(a + 1, a + n + 1, cmp3); int gg = 0;
memset(s, 0, sizeof(s)); memset(num, 0, sizeof(num));
for(int i = 1; i <= n; i++) change(i, mc1[i]);
for(int i = 1; i <= tp; i++) {
while(gg < n && a1[i].l > a[gg + 1].l - a[gg + 1].s + 1) ++gg, change(a[gg].l, a[gg].l - a[gg].s), cnum(a[gg].l, 1);
ans[a1[i].id] += getsum(a1[i].r) - getsum(a1[i].l - 1) - (LL)(getn(a1[i].r) - getn(a1[i].l - 1)) * (a1[i].l - 1);
}
for(int i = 1; i < n; i++) a[i].l = i, a[i].s = mc2[i];
sort(a + 1, a + n, cmp3); gg = 0;
memset(s, 0, sizeof(s)); memset(num, 0, sizeof(num));
for(int i = 1; i < n; i++) change(i, mc2[i]);
for(int i = 1; i <= tp; i++) {
if(a1[i].l == a1[i].r) continue;
while(gg < n - 1 && a1[i].l > a[gg + 1].l - a[gg + 1].s + 1) ++gg, change(a[gg].l, a[gg].l - a[gg].s), cnum(a[gg].l, 1);
ans[a1[i].id] += getsum(a1[i].r - 1) - getsum(a1[i].l - 1) - (LL)(getn(a1[i].r - 1) - getn(a1[i].l - 1)) * (a1[i].l - 1);
}
for(int i = 1; i <= n; i++) a[i].l = i, a[i].s = mc1[i];
sort(a + 1, a + n + 1, cmp4); gg = 0;
memset(s, 0, sizeof(s)), memset(num, 0, sizeof(num));
for(int i = 1; i <= n; i++) change(i, mc1[i]);
for(int i = 1; i <= tp; i++) {
while(gg < n && a2[i].r < a[gg + 1].l + a[gg + 1].s - 1) ++gg, change(a[gg].l, -a[gg].l - a[gg].s), cnum(a[gg].l, 1);
ans[a2[i].id] += getsum(a2[i].r) - getsum(a2[i].l - 1) + (LL)(getn(a2[i].r) - getn(a2[i].l - 1)) * (a2[i].r + 1);
}
for(int i = 1; i < n; i++) a[i].l = i, a[i].s = mc2[i];
sort(a + 1, a + n, cmp4); gg = 0;
memset(s, 0, sizeof(s)), memset(num, 0, sizeof(num));
for(int i = 1; i <= n; i++) change(i, mc2[i]);
for(int i = 1; i <= tp; i++) {
if(a2[i].l == a2[i].r) continue;
while(gg < n && a2[i].r < a[gg + 1].l + a[gg + 1].s) ++gg, change(a[gg].l, -a[gg].l - a[gg].s), cnum(a[gg].l, 1);
ans[a2[i].id] += getsum(a2[i].r - 1) - getsum(a2[i].l - 1) + (LL)(getn(a2[i].r - 1) - getn(a2[i].l - 1)) * a2[i].r;
} for(int i = 1; i <= m; i++) printf("%lld\n", ans[i]);
return 0;
}