BZOJ4358 perma


思路

其实维护不同操作的分块,它的核心代码依旧是【排序 】与【l , r l, r l,r 移动 】的那几行。不同的就是 a d d ( i ) , d e l ( i ) add(i), del(i) add(i),del(i) 中的数据结构。

我们看到要求最大连续段,就应该可以想到用线段树来维护。

线段树要满足以下操作:

  1. 单点修改某个值 :就是用 0 / 1 0/1 0/1 表示当前区间是否存在某个数;
  2. 合并区间最长连续段:记录每个区间的【最长连续段 m x [ o ] mx[o] mx[o]】【最长连续前缀 p r e [ o ] pre[o] pre[o]】【最长连续后缀 s u f [ o ] suf[o] suf[o]】,这几个数组在单点修改时维护即可;
  3. 求值域在 [ 1 , n ] [1, n] [1,n] 内的最长连续段:返回 m x [ 1 ] mx[1] mx[1] 即可。

时间复杂度:移动一次的复杂度为 O ( l o g ( n ) ) O(log(n)) O(log(n)),总得时间复杂度就是 O ( n n × l o g ( n ) ) O(n \sqrt{n} \times log(n)) O(nn ×log(n))。


代码

cpp 复制代码
#include <bits/stdc++.h>

using namespace std;

const int maxn = 5e4 + 7;

int n, m, a[maxn];
struct query {int l, r, id;} q[maxn];

#define id(x) (((x) - 1) / sz + 1)
int sz, l, r;
bool cmp(query x, query y) {
	if (id(x.l) != id(y.l)) return id(x.l) < id(y.l);
	if (id(x.l) & 1) return x.r < y.r;
	return x.r > y.r;
}

#define ls (o << 1)
#define rs (o << 1 | 1)
#define mid ((l + r) >> 1)
struct SegmentTree {
	int mx[maxn << 2], pre[maxn << 2], suf[maxn << 2];
	void mdf(int o, int l, int r, int q, int v) {
		if (l == r) {
			mx[o] += v;
			pre[o] += v;
			suf[o] += v;
			return ;
		}
		if (q <= mid) mdf(ls, l, mid, q, v);
		else mdf(rs, mid + 1, r, q, v);
		
		// 合并求最长段
		pre[o] = pre[ls], suf[o] = suf[rs];
		if (mx[ls] == mid - l + 1) pre[o] = mx[ls] + pre[rs];
		if (mx[rs] == r - mid) suf[o] = mx[rs] + suf[ls];
		mx[o] = max(suf[ls] + pre[rs], max(mx[ls], mx[rs]));
	}
} sg;
inline void add(int x) {sg.mdf(1, 1, n, a[x], 1);}
inline void del(int x) {sg.mdf(1, 1, n, a[x], -1);}
int ans[maxn];
int main() {
	scanf("%d%d", &n, &m), sz = sqrt(n);
	for (int i = 1; i <= n; ++i) scanf("%d", a + i);
	for (int i = 1; i <= m; ++i) scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
	sort(q + 1, q + m + 1, cmp);
	
	l = q[1].l, r = q[1].r;
	for (int i = l; i <= r; ++i) add(i);
	ans[q[1].id] = sg.mx[1];
	
	for (int i = 2; i <= m; ++i) {
		while (l < q[i].l) del(l++);
		while (l > q[i].l) add(--l);
		while (r < q[i].r) add(++r);
		while (r > q[i].r) del(r--);
		ans[q[i].id] = sg.mx[1];
	}
	for (int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
	return 0;
}