斩尽牛杂
Analysis
区间本质不同子串长度和
其实就是区间本质不同子串个数 Plus 版。
剩下的就是看怎么把数量转化成长度了。
Solution
回顾整个操作,每次我们在 \(access\) 的时候是取消上次的贡献,最后统一全局加。
那怎么刻画长度??我们发现无论是哪种修改,都是直接加一个等差数列。那这样的话树状数组不好使了,改用线段树。
维护两个东西,公差和起始位置。
然后两个小细节:
-
公差是 \(-1\) ,因为我们区间修改的时候刻画的是起始位置,结束位置相同的话,越靠前长度越大。
-
注意下消去贡献的时候因为变成了加上负数,所以公差变成 \(1\) 。
Code
Code
#include
using namespace std;
typedef long long ll;
const int N = 4e5 + 10, M = 2e6 + 10;
int n, pos[N]; ll ans[N];
struct seq {
int l, r, id;
bool operator < (const seq &it) const {
return r < it.r;
}
} a[N];
inline int read() {
char ch = getchar();
int s = 0, w = 1;
while (!isdigit(ch)) {if (ch == '-') w = -1; ch = getchar();}
while (isdigit(ch)) {s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar();}
return s * w;
}
struct SAM {
int n, cnt, las, len[N], link[N], ch[N][26];
char s[N]; int tong[N], rk[N];
inline void init() {cnt = las = 1; memset(ch[1], 0, sizeof(ch[1]));}
inline void SAM_stru(int c) {
int cur = ++cnt, p = las;
memset(ch[cur], 0, sizeof(ch[cur]));
las = cur;
len[cur] = len[p] + 1;
while (p && !ch[p][c]) ch[p][c] = cur, p = link[p];
if (!p) {link[cur] = 1; return ;}
int q = ch[p][c];
if (len[p] + 1 == len[q]) {link[cur] = q; return ;}
int clo = ++cnt;
link[clo] = link[q]; len[clo] = len[p] + 1;
link[q] = link[cur] = clo;
memcpy(ch[clo], ch[q], sizeof(ch[clo]));
while (p && ch[p][c] == q) ch[p][c] = clo, p = link[p];
}
inline void Tong_sort() {
for (int i = 1; i <= cnt; ++i) ++tong[len[i]];
for (int i = 1; i <= cnt; ++i) tong[i] += tong[i - 1];
for (int i = 1; i <= cnt; ++i) rk[tong[len[i]]--] = i;
}
} s;
struct mdzz {
ll gc, p;
mdzz(ll x = 0, ll y = 0) {gc = x; p = y;}
mdzz operator += (const mdzz &it) {
gc += it.gc; p += it.p; return *this;
}
inline ll summ(ll l, ll r) {
return (r - l + 1) * (p + gc * l + p + gc * r) / 2;
}
};
struct SGT {
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
ll sum[M]; mdzz lzy[M];
inline void pushup(int x) {sum[x] = sum[ls(x)] + sum[rs(x)];}
inline void pushdown(int x, int l, int r) {
if (lzy[x].gc || lzy[x].p) {
int mid = (l + r) >> 1;
lzy[ls(x)] += lzy[x]; sum[ls(x)] += lzy[x].summ(l, mid);
lzy[rs(x)] += lzy[x]; sum[rs(x)] += lzy[x].summ(mid + 1, r);
lzy[x] = mdzz(0, 0);
}
}
inline void modify(int x, int l, int r, int L, int R, mdzz k) {
if (L > R) return ;
if (L <= l && r <= R) {
lzy[x] += k, sum[x] += k.summ(l, r);
return ;
}
pushdown(x, l, r);
int mid = (l + r) >> 1;
if (L <= mid) modify(ls(x), l, mid, L, R, k);
if (R > mid) modify(rs(x), mid + 1, r, L, R, k);
pushup(x);
}
inline ll query(int x, int l, int r, int L, int R) {
if (L > R) return 0;
if (L <= l && r <= R) return sum[x];
pushdown(x, l, r);
int mid = (l + r) >> 1;
ll res = 0;
if (L <= mid) res += query(ls(x), l, mid, L, R);
if (R > mid) res += query(rs(x), mid + 1, r, L, R);
return res;
}
#undef ls
#undef rs
} seg;
struct LCT {
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
int ch[N][2], fa[N], xr[N], cov[N], val[N], len[N], top, sta[N];
inline void build() {
val[0] = 1e9;
for (int i = 1; i <= s.cnt; ++i) {
fa[i] = s.link[i];
val[i] = len[i] = s.len[fa[i]] + 1;
xr[i] = cov[i] = ls(i) = rs(i) = 0;
}
}
inline void pushcov(int x, int k) {xr[x] = cov[x] = k;}
inline void pushup(int x) {
val[x] = min(len[x], min(val[ls(x)], val[rs(x)]));
}
inline void pushdown(int x) {
if (cov[x]) {
if (ls(x)) pushcov(ls(x), cov[x]);
if (rs(x)) pushcov(rs(x), cov[x]);
cov[x] = 0;
}
}
inline bool nroot(int x) {return ls(fa[x]) == x || rs(fa[x]) == x;}
inline void rotate(int x) {
int y = fa[x], z = fa[y], k = rs(y) == x, w = ch[x][!k];
if (nroot(y)) ch[z][rs(z) == y] = x;
ch[x][!k] = y; ch[y][k] = w;
if (w) fa[w] = y;
fa[y] = x; fa[x] = z; pushup(y); pushup(x);
}
inline void splay(int x) {
int y = x, z; top = 0;
sta[++top] = y;
while (nroot(y)) sta[++top] = y = fa[y];
while (top) pushdown(sta[top--]);
while (nroot(x)) {
y = fa[x]; z = fa[y];
if (nroot(y)) rotate((ls(y) == x) ^ (ls(z) == y) ? x : y);
rotate(x);
}
}
inline void access(int x, int k) {
int y = 0;
while (x) {
splay(x);
int st = xr[x] - s.len[x] + 1;
if (xr[x]) seg.modify(1, 1, s.n, st, xr[x] - val[x] + 1, mdzz(1, -(xr[x] + 1)));
rs(x) = y; y = x, x = fa[x];
}
pushcov(y, k); seg.modify(1, 1, s.n, 1, k, mdzz(-1, k + 1));
}
#undef ls
#undef rs
} lct;
int main() {
scanf("%s", s.s + 1); s.n = strlen(s.s + 1); s.init();
for (int i = 1; i <= s.n; ++i) {
s.SAM_stru(s.s[i] - 'a'); pos[i] = s.las;
}
s.Tong_sort();
n = read();
for (int i = 1; i <= n; ++i) {
a[i] = (seq) {read(), read(), i};
}
sort(a + 1, a + 1 + n);
lct.build();
for (int i = 1, j = 1; i <= n; ++i) {
while (j <= a[i].r) lct.access(pos[j], j), ++j;
ans[a[i].id] = seg.query(1, 1, s.n, a[i].l, a[i].r);
}
for (int i = 1; i <= n; ++i) printf("%lld\n", ans[i]);
return 0;
}