斩尽牛杂

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;
}

posted @ 2022-03-15 22:28  Illusory_dimes  阅读(187)  评论(0编辑  收藏  举报