码迷,mamicode.com
首页 > 其他好文 > 详细

CF1098F Ж-function [后缀自动机+扫描线]

时间:2020-05-02 18:44:09      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:lin   char s   glin   data   vector   后缀自动机   char   local   rom   

这题好仙啊,不会。后面看懂了再来填坑吧。

// by Isaunoya
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 4e5 + 58;
using ll = long long;
struct smt {
	int n, size, rt;
	int ls[maxn << 1], rs[maxn << 1];
	ll tag[maxn << 1];
	ll cnt[maxn << 1], sum[maxn << 1];

	void init(int sz, int *tmp) {
		size = rt = 0, n = sz, bld(rt, 1, n, tmp);
	}

	void up(int p) {
		sum[p] = sum[ls[p]] + sum[rs[p]];
	}
	
	void bld(int &p, int l, int r, int *tmp) {
		p = ++ size;
		if(l == r) {
			cnt[p] = tmp[l];
			return;
		}
		int mid = l + r >> 1;
		bld(ls[p], l, mid, tmp);
		bld(rs[p], mid + 1, r, tmp);
		cnt[p] = cnt[ls[p]] + cnt[rs[p]];
	}

	void down(int p) {
		if(tag[p]) {
			tag[ls[p]] += tag[p], sum[ls[p]] += tag[p] * cnt[ls[p]];
			tag[rs[p]] += tag[p], sum[rs[p]] += tag[p] * cnt[rs[p]];
			tag[p] = 0;
		}
	}
	void mdf(int p, int ql, int qr, int l, int r, int v) {
		if(ql <= l && r <= qr) {
			tag[p] += v, sum[p] += v * cnt[p];
			return;
		}
		down(p);
		int mid = l + r >> 1;
		if(ql <= mid) mdf(ls[p], ql, qr, l, mid, v);
		if(qr > mid) mdf(rs[p], ql, qr, mid + 1, r, v);
		up(p);
	}
	void mdf(int ql, int qr, int v) {
		mdf(rt, ql, qr, 1, n, v);
	}
	ll qry(int p, int ql, int qr, int l, int r) {
		if(ql <= l && r <= qr) {
			return sum[p];
		}
		down(p);
		int mid = l + r >> 1;
		ll ans = 0;
		if(ql <= mid) ans += qry(ls[p], ql, qr, l, mid);
		if(qr > mid) ans += qry(rs[p], ql, qr, mid + 1, r);
		return ans;
	}
	int qry(int ql, int qr) {
		return qry(rt, ql, qr, 1, n);
	}
	ll qry(int p, int x, int l, int r) {
		if(l == r) {
			return tag[p];
		}
		down(p);
		int mid = l + r >> 1;
		if(x <= mid) return qry(ls[p], x, l, mid);
		else return qry(rs[p], x, mid + 1, r);
	}
	ll qry(int x) { return qry(rt, x, 1, n); }
} smt;

struct BIT {
	int n;
	vector <ll> c;
	void init(int _n) {
		n = _n + 1;
		c.resize(n + 1);
	}
	int low(int x) {
		return x & -x;
	}
	void u(int x, int y) {
		for(; x <= n; x += low(x)) c[x] += y;
	}
	ll q(int x) {
		ll ans = 0;
		for(; x; x ^= low(x)) ans += c[x];
		return ans;
	}
	ll qry(int x) { return q(x); }
	ll qry(int l, int r) {
		if(l > r)
			return 0;
		return q(r) - q(l - 1);
	}
} al[2], pt[2];

int pos[maxn], rev[maxn];
struct suffixautomaton {
	int ch[maxn][26], fa[maxn], len[maxn];
	int las, cnt;
	suffixautomaton() { las = cnt = 1; }

	void ins(int c, int id) {
		int p = las, np = las = ++cnt;
		pos[np] = id;
		len[np] = len[p] + 1;
		for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
		if(!p) {
			fa[np] = 1;
		} else {
			int q = ch[p][c];
			if(len[q] == len[p] + 1) {
				fa[np] = q;
			} else {
				int nq = ++cnt;
				len[nq] = len[p] + 1;
				fa[nq] = fa[q], fa[q] = fa[np] = nq;
				memcpy(ch[nq], ch[q], sizeof(ch[q]));
				for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
			}
		}
	}
} sam;

int n, t, len;
char s[maxn];
int dep[maxn], f[maxn][22];
vector <int> g[maxn];
int ql[maxn], qr[maxn], from[maxn];

int sz[maxn], fa[maxn], son[maxn];
void dfs(int u) {
	sz[u] = 1;
	for(int v: g[u]) {
		if(v ^ fa[u]) {
			fa[v] = u, dfs(v), sz[u] += sz[v];
			if(sz[v] > sz[son[u]]) son[u] = v;
		}
	}
}

int top[maxn], dfn[maxn];
//dfo[maxn];
int idx = 0;
void dfs(int u, int t) {
	top[u] = t, dfn[u] = ++ idx;
	if(son[u]) dfs(son[u], t);
	for(int v: g[u])
		if(!top[v]) dfs(v, v);
//	dfo[u] = idx;
}

ll ans[maxn];

void Scanninglinefir() {
	static int tmp[maxn];
	for(int i = 1 ; i <= n ; i ++) {
		tmp[dfn[i]] = dep[i] - dep[fa[i]];
	}
	smt.init(n, tmp);
	static vector <pair<pair<int, int>, int>> q[maxn];
	for(int i = 1 ; i <= t ; i ++) {
		q[ql[i]].push_back(make_pair(make_pair(from[i], qr[i] - ql[i] + 1), i));
	}
	for(int i = 1 ; i <= len ; i ++) {
		auto query = [&](pair<int, int> x) {
			ll ans = 1ll * (x.second - dep[fa[x.first]]) * smt.qry(dfn[x.first]);
			int pos = fa[x.first];
			while(pos) {
				ans += smt.qry(dfn[top[pos]], dfn[pos]), pos = fa[top[pos]];
			}
			return ans;
		};
		for(auto x : q[i]) {
			ans[x.second] -= query(x.first);
		}
		int pos = rev[i];
		while(pos) {
			smt.mdf(dfn[top[pos]], dfn[pos], 1), pos = fa[top[pos]];
		}
	}
}

void Scanninglinesec() {
	static vector <pair<int, int>> mdf[maxn];
	static vector <pair<pair<int, int>, int>> qry[maxn];
	for(int i = 1 ; i <= len ; i ++) {
		int pos = rev[i];
		while(pos) {
			mdf[top[pos]].emplace_back(dep[pos], i), pos = fa[top[pos]];
		}
	}
	for(int i = 1 ; i <= t ; i ++) {
		int pos = from[i];
		while(pos) {
			if(pos == from[i]) {
				qry[top[pos]].emplace_back(make_pair(qr[i] - ql[i] + 1, qr[i] + 1), i);
			} else {
				qry[top[pos]].emplace_back(make_pair(dep[pos], qr[i] + 1), i);
			}
			pos = fa[top[pos]];
		}
	}
	al[0].init(len * 2 + 2), al[1].init(len * 2 + 2);
	pt[0].init(len * 2 + 2), pt[1].init(len * 2 + 2);
	for(int i = 1 ; i <= n ; i ++) {
		if(top[i] != i) { continue; }
		int st = dep[fa[i]] + 1;
		sort(mdf[i].begin(), mdf[i].end()), reverse(mdf[i].begin(), mdf[i].end());
		sort(qry[i].begin(), qry[i].end()), reverse(qry[i].begin(), qry[i].end());
		vector <pair<int, int>> bak = mdf[i];
		for(auto x: bak) {
			al[0].u(x.second, x.second), al[1].u(x.second, 1);
		}
		while(!mdf[i].empty() || !qry[i].empty()) {
			if(mdf[i].empty() || (!qry[i].empty() && qry[i].back().first.first <= mdf[i].back().first)) {
				pair <int, int> x = qry[i].back().first;
				int pos = qry[i].back().second;
				ans[pos] += 1ll * pt[1].qry(x.second) * x.second + pt[0].qry(x.second);
				int tmp = x.second - x.first;
				if(tmp >= 1) {
					ans[pos] += al[1].qry(1, tmp) * (x.first - st + 1);
				}
				tmp = max(tmp, 0ll);
				ans[pos] += 1ll * al[1].qry(tmp + 1, x.second - st) * (x.second - st + 1) - al[0].qry(tmp + 1, x.second - st);
				qry[i].pop_back();
			} else {
				pair <int, int> x = mdf[i].back();
				al[0].u(x.second, -x.second), al[1].u(x.second, -1);
				pt[0].u(st + x.second, -(st + x.second - 1));
				pt[0].u(x.first + x.second + 1, st + x.second - 1 + x.first - st + 1);
				pt[1].u(st + x.second, 1), pt[1].u(x.first + x.second + 1, -1);
				mdf[i].pop_back();
			}
		}
		for(auto x: bak) {
			pt[0].u(st + x.second, st + x.second - 1);
			pt[0].u(x.first + x.second + 1, -(st + x.second - 1 + x.first - st + 1));
			pt[1].u(st + x.second, -1), pt[1].u(x.first + x.second + 1, 1);
		}
	}	
}

signed main() {
#ifdef LOCAL
	freopen("testdata.in", "r", stdin);
#endif
	scanf("%s", s + 1);
	len = strlen(s + 1);
	for(int i = len ; i ; i --) {
		sam.ins(s[i] - ‘a‘, i);
	}
	n = sam.cnt;
	for(int i = 1 ; i <= n ; i ++) {
		dep[i] = sam.len[i];
		if(pos[i]) rev[pos[i]] = i;
	}
	for(int i = 2 ; i <= n ; i ++) {
		g[sam.fa[i]].push_back(i);
	}
	dfs(1),	dfs(1, 1);
	scanf("%lld", &t);
	for(int i = 1 ; i <= t ; i ++) {
		int l, r; scanf("%lld %lld", &l, &r);
		ql[i] = l, qr[i] = r;
	}
	for(int i = 1 ; i <= n ; i ++) {
		f[i][0] = sam.fa[i];
	}
	for(int j = 1 ; j <= 20 ; j ++)
		for(int i = 1 ; i <= n ; i ++) f[i][j] = f[f[i][j - 1]][j - 1];
	for(int i = 1 ; i <= t ; i ++) {
		int l = ql[i], r = qr[i], goal = r - l + 1, p = rev[l];
		for(int j = 20; ~j; -- j) if(f[p][j] && dep[f[p][j]] >= goal) p = f[p][j];
		from[i] = p;
	}
	Scanninglinefir(), Scanninglinesec();
	for(int i = 1 ; i <= t ; i ++) printf("%lld\n", ans[i]);
	return 0;
}

CF1098F Ж-function [后缀自动机+扫描线]

标签:lin   char s   glin   data   vector   后缀自动机   char   local   rom   

原文地址:https://www.cnblogs.com/Isaunoya/p/12818907.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!