【BZOJ 3809】Gty的二逼妹子序列

这个莫队如果用线段树来维护的话,复杂度是$O(n\sqrt{n}logn+qlogn)$

很明显,可以看出来莫队每次$O(1)$的移动因为套上了线段树变成了$O(logn)$,但莫队移动的总数是非常大的,所以乘起来复杂度就上天了。

那么有没有一种方法在修改上能够比线段树更快,同时又能相比暴力较快地回答询问呢?

我们可以用分块,把序列分成$\sqrt{n}$块,修改的复杂度是$O(1)$,回答询问的复杂度是$O(\sqrt{n})$

这样用分块代替线段树总复杂度就变成了$O(n\sqrt{n}+q\sqrt{n})$,然后就AC了~

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100003;
const int M = 1000003;
void read(int &k) {
	k = 0; int fh = 1; char c = getchar();
	for(; c < '0' || c > '9'; c = getchar())
		if (c == '-') fh = -1;
	for(; c >= '0' && c <= '9'; c = getchar())
		k = (k << 1) + (k << 3) + c - '0';
	k = k * fh;
}

struct node {int l, r, a, b, id;} Q[M];
int w[N], bel[N], n, m, sum[N], A[M], c[N];

bool cmp(node A, node B) {return bel[A.l] == bel[B.l] ? A.r < B.r : A.l < B.l;}
void update(int a, int flag) {
	c[a] += flag;
	if (flag == -1 && c[a] == 0) --sum[bel[a]];
	if (flag == 1 && c[a] == 1) ++sum[bel[a]];
}
int QQ(int l, int r) {
	int bl = bel[l], br = bel[r], ret = 0;
	if (bl == br) {
		for(int i = l; i <= r; ++i)
			if (c[i] > 0) ++ret;
		return ret;
	}
	for(int i = l; bel[i] == bel[l]; ++i)
		if (c[i] > 0) ++ret;
	for(int i = r; bel[i] == bel[r]; --i)
		if (c[i] > 0) ++ret;
	for(int i = bel[l] + 1; i < bel[r]; ++i)
		ret += sum[i];
	return ret;
}

int main() {
	read(n); read(m);
	for(int i = 1; i <= n; ++i) read(w[i]);
	for(int i = 1; i <= m; ++i) {read(Q[i].l); read(Q[i].r); read(Q[i].a); read(Q[i].b); Q[i].id = i;}
	
	int t = sqrt(n + 0.5), cnt = 1, tmp = 1;
	for(int i = 1; i <= n; ++i) {
		bel[i] = tmp;
		++cnt; if (cnt > t) {cnt = 1; ++tmp;}
	}
	
	sort(Q + 1, Q + m + 1, cmp);
	
	int l = 1, r = 0, tol, tor;
	for(int i = 1; i <= m; ++i) {
		tol = Q[i].l; tor = Q[i].r;
		while (l < tol) update(w[l++], -1);
		while (l > tol) update(w[--l], 1);
		while (r < tor) update(w[++r], 1);
		while (r > tor) update(w[r--], -1);
		A[Q[i].id] = QQ(Q[i].a, Q[i].b);
	}
	
	for(int i = 1; i <= m; ++i) printf("%d\n", A[i]);
	
	return 0;
}

分块大法好

posted @ 2016-05-10 14:58  abclzr  阅读(329)  评论(0编辑  收藏  举报