BZOJ3682: Phorni(后缀平衡树)

传送门
后缀平衡树模板题
用平衡树维护每一个后缀的排名
关键在于查询两个后缀的大小
可以用二分加hash,复杂度 \(log^2n\) 插入
或者:
每次前面插入一个字符,先比较两个后缀第一个字符的大小
而后面的大小我们已经在平衡树上维护好了
像这样分配权值

给树上每个子树一个实数权值区间 \([l,r]\),这个点权值为 \(mid=\frac{l+r}{2}\)
左子树 \([l,mid]\) 右子树 \([mid,r]\)

那么可以做到 \(O(1)\) 比较
只需要选择一个树高 \(log\) 的树(treap/替罪羊树)使得满足精度要求即可
最后用线段树维护一下每个幻影的最小的后缀

# include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn(1e6 + 5);
const double alpha(0.75);

int ls[maxn], rs[maxn], rt, tot, size[maxn], que[maxn], cnt;
double val[maxn];
int mn[maxn << 1], id[maxn], n, m, p[maxn], pos[maxn];
char s[maxn];

void Dfs(int u) {
	if (!u) return;
	Dfs(ls[u]), que[++cnt] = u, Dfs(rs[u]);
}

int Build(int l, int r, double vl, double vr) {
	if (l > r) return 0;
	double midv;
	int mid, o;
	mid = (l + r) >> 1, o = que[mid], midv = (vl + vr) * 0.5;
	ls[o] = rs[o] = 0, val[o] = midv;
	ls[o] = Build(l, mid - 1, vl, midv);
	rs[o] = Build(mid + 1, r, midv, vr);
	size[o] = size[ls[o]] + size[rs[o]] + 1;
	return o;
}

int Rebuild(int x, double vl, double vr) {
	cnt = 0, Dfs(x);
	return Build(1, cnt, vl, vr);
}

inline int Compare(int x, int y) {
	return (s[x] ^ s[y]) ? s[x] < s[y] : val[id[x - 1]] < val[id[y - 1]];
}

int Insert(int &x, double vl, double vr, int ps) {
	double midv;
	int ret;
	midv = (vl + vr) * 0.5;
	if (!x) {
		x = ++tot, val[x] = midv, pos[x] = ps, size[x] = 1;
		return x;
	}
	if (alpha * size[x] < max(size[ls[x]], size[rs[x]])) x = Rebuild(x, vl, vr);
	if (Compare(ps, pos[x])) ret = Insert(ls[x], vl, midv, ps);
	else ret = Insert(rs[x], midv, vr, ps);
	size[x] = size[ls[x]] + size[rs[x]] + 1;
	return ret;
}

void Modify(int x, int l, int r, int ps) {
	int mid;
	if (l == r) mn[x] = l;
	else {
		mid = (l + r) >> 1;
		ps <= mid ? Modify(x << 1, l, mid, ps) : Modify(x << 1 | 1, mid + 1, r, ps);
		mn[x] = val[id[p[mn[x << 1]]]] <= val[id[p[mn[x << 1 | 1]]]] ? mn[x << 1] : mn[x << 1 | 1];
	}
}

int Query(int x, int l, int r, int ql, int qr) {
	int mid, ret, v;
	if (ql <= l && qr >= r) return mn[x];
	mid = (l + r) >> 1, ret = -1, v;
	if (ql <= mid) ret = Query(x << 1, l, mid, ql, qr);
	if (qr > mid) {
		v = Query(x << 1 | 1, mid + 1, r, ql, qr);
		ret = (ret == -1 || val[id[p[v]]] < val[id[p[ret]]]) ? v : ret;
	}
	return ret;
}

int main() {
	int i, l, r, k, ans, type, len;
	char op;
	scanf("%d%d%d%d %s", &n, &m, &len, &type, s + 1);
	reverse(s + 1, s + len + 1), val[0] = -1;
	for (i = 1; i <= len; ++i) id[i] = Insert(rt, 0, 1, i);
	for (i = 1; i <= n; ++i) scanf("%d", &p[i]), Modify(1, 1, n, i);
	ans = 0;
	for (i = 1; i <= m; ++i) {
		scanf(" %c", &op);
		if (op == 'I') {
			scanf(" %d", &k);
			if (type) k = (k ^ ans);
			s[++len] = k + 'a';
			id[len] = Insert(rt, 0, 1, len);
		}
		else if (op == 'C') {
			scanf("%d%d", &l, &r);
			p[l] = r, Modify(1, 1, n, l);
		}
		else scanf("%d%d", &l, &r), printf("%d\n", ans = Query(1, 1, n, l, r));
	}
    return 0;
}
posted @ 2019-01-12 16:47  Cyhlnj  阅读(224)  评论(0编辑  收藏  举报