1. 程式人生 > >[洛谷P4688][Ynoi2016]掉進兔子洞

[洛谷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;
}