bzoj 2743 [HEOI2012]采花 离线处理+树状数组

题面

题目传送门

解法

\(nxt_i\)\(a_i\)下一次出现的位置

把所有询问按左端点排序

处理完所有以\(i\)开始的询问后,我们把\(nxt_i\)的影响删除,把\(nxt_{nxt_i}\)加上

这样就能保证计算入答案的必然是这个区间里第二次出现的

树状数组维护即可

时间复杂度:\(O(q\ log\ q+q\ log\ n)\)

代码

#include <bits/stdc++.h>
#define N 2000010
using namespace std;
template <typename node> void read(node &x) {
	x = 0; int f = 1; char c = getchar();
	while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
	while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Node {
	int l, r, id;
	bool operator < (const Node &a) const {
		return l < a.l;
	}
} b[N];
int n, c, q, a[N], f[N], s[N], ans[N], las[N], nxt[N], tmp[N];
int lowbit(int x) {return x & -x;}
void modify(int x, int val) {
	for (int i = x; i <= n; i += lowbit(i))
		f[i] += val;
}
int query(int x) {
	int ret = 0;
	for (int i = x; i; i -= lowbit(i)) ret += f[i];
	return ret;
}
int main() {
	read(n), read(c), read(q);
	for (int i = 1; i <= n; i++) read(a[i]);
	for (int i = n; i; i--) nxt[i] = las[a[i]], las[a[i]] = i;
	for (int i = 1; i <= c; i++)
		if (nxt[las[i]]) modify(nxt[las[i]], 1);
	for (int i = 1; i <= q; i++) read(b[i].l), read(b[i].r), b[i].id = i;
	sort(b + 1, b + q + 1); int now = 1;
	for (int i = 1; i <= q; i++) {
		while (now < b[i].l) {
			if (nxt[now]) modify(nxt[now], -1);
			if (nxt[nxt[now]]) modify(nxt[nxt[now]], 1);
			now++;
		}
		ans[b[i].id] = query(b[i].r) - query(b[i].l - 1);
	}
	for (int i = 1; i <= q; i++) cout << ans[i] << "\n";
	return 0;
}

posted @ 2018-08-14 23:20  谜のNOIP  阅读(111)  评论(0编辑  收藏  举报