[洛谷P4688][Ynoi2016]掉进兔子洞

题目大意:给定一个$n(n\leqslant10^5)$序列,$m(m\leqslant10^5)$个询问,每个询问给出$l_1,r_1,l_2,r_2,l_3,r_3$。令$s$为该三个区间的交集的大小,则输出$|[l_1,r_1]|+|[l_2,r_2]|+|[l_3,r_3]|−3|s|$

题解:$|[l_1,r_1]|+|[l_2,r_2]|+|[l_3,r_3]|$这一部分比较好求,主要就是求$|s|$,$s$是这三个区间元素的并集,可以想到用$bitset$,但是$bitset$似乎只可以求有多少种相同元素,而不可以求有多少个相同元素,这时可以改一下离散化的方式,排序后不要去重,这时就可以用这个数和这个数现在已经出现的次数定下一个唯一确定位置。这样就可以完成求并集的过程了。

这里可以用莫队来求每个数出现次数以及那一个元素出现的集合。但是发现空间复杂度是$O(\dfrac{nm}{\omega})$,开不下。可以把询问分成$3$次进行处理,就可以了

卡点:把一个$maxm$打成了$maxn$,然后$RE$

C++ Code:

#include <algorithm>
#include <bitset>
#include <cstdio>
#include <cctype>
#include <iostream>
namespace __IO {
	namespace R {
		int x, ch;
		inline int read() {
			while (isspace(ch = getchar()));
			for (x = ch & 15; isdigit(ch = getchar()); ) x = x * 10 + (ch & 15);
			return x;
		}
	}
}
using __IO::R::read;

#define maxn 100010
#define maxm 35000

int n, m;
int s[maxn], v[maxn];
std::bitset<maxn> ans[maxm + 10], res;
struct Query {
	int l, r, id;
	inline friend bool operator < (const Query &lhs, const Query &rhs) {
		return lhs.l >> 8 == rhs.l >> 8 ? (lhs.l >> 8 & 1 ? lhs.r > rhs.r : lhs.r < rhs.r) : lhs.l < rhs.l;
	}
} q[maxm * 3 + 10];

int tmpans[maxm + 10], cnt[maxn];

inline void add(int x) {res.set(x + cnt[x]); cnt[x]++;}
inline void del(int x) {cnt[x]--; res.reset(x + cnt[x]);}

void solve() {
	int tot = 0;
	for (int i = 1; m && i < maxm; i++, m--) {
		ans[i].set(); tmpans[i] = 0;
		q[++tot].id = i, q[tot].l = read(), q[tot].r = read(), tmpans[i] += q[tot].r - q[tot].l + 1;
		q[++tot].id = i, q[tot].l = read(), q[tot].r = read(), tmpans[i] += q[tot].r - q[tot].l + 1;
		q[++tot].id = i, q[tot].l = read(), q[tot].r = read(), tmpans[i] += q[tot].r - q[tot].l + 1;
	}
	res.reset();
	for (int i = 1; i <= n; i++) cnt[i] = 0;
	int l = 1, r = 0;
	std::sort(q + 1, q + tot + 1);
	for (int i = 1; i <= tot; i++) {
		while (r < q[i].r) add(s[++r]);
		while (l > q[i].l) add(s[--l]);
		while (r > q[i].r) del(s[r--]);
		while (l < q[i].l) del(s[l++]);
		ans[q[i].id] &= res;
	}
	const int M = tot / 3;
	for (int i = 1; i <= M; i++) printf("%d\n", tmpans[i] - ans[i].count() * 3);
}

int main() {
	n = read(), m = read();
	for (int i = 1; i <= n; i++) v[i] = s[i] = read();
	std::sort(v + 1, v + n + 1);
	for (int i = 1; i <= n; i++) s[i] = std::lower_bound(v + 1, v + n + 1, s[i]) - v;
	while (m) solve();
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10120966.html
今日推荐