Live2D

题解 掉进兔子洞

题目传送门

题目大意

给出\(n\)个数,\(m\)次查询,查询互相独立,每次查询给出三个区间\([l1,r1],[l2,r2],[l3,r3]\),求出三个区间一个一个删去相同数字之后剩余数的个数。

思路

好秒啊!!!

首先我们可以离散化,但是与普通离散化不同的是,这里离散化的结果实际上是小于等于这个数的个数。显然这样并不会影响结果。至于为什么下面解释。

我们考虑如何求出在三个区间都出现的数的个数。诶?似乎可以\(\texttt{bitset}\)+莫队?但是我们发现我们没有办法统计出现次数诶?但是其实我们统计一下需要修改的点\(p\)已经出现的次数为\(cnt\),把\(bitset_{p-cnt}\)设为\(1\)即可。至于为什么呢?这是因为这样做的话两个不同数字显然不会产生影响,这也是为什么上面离散化的值取的是小于等于这个数的个数,而不是小于这个数的个数。

但是直接这样做会爆空间,我们可以循环利用一下,查询分成\(3\)次即可。

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define MAXN 100005
#define MAXM 34010

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

struct node{
	int l,r,t;
	void Putin(int g){read (l,r),t = g;}
}q[MAXM * 3]; 

bool cmp1 (node a,node b){return a.l < b.l;}
bool cmp2 (node a,node b){return a.r < b.r;}

map <int,int> mp;
bitset <MAXN> nb,ans[MAXM];
int n,m,tot = 1,a[MAXN],cnt[MAXN],nans[MAXM];

void ins (int p){nb[p - cnt[p]] = 1,cnt[p] ++;}
void del (int p){cnt[p] --,nb[p - cnt[p]] = 0;}

void Solve (){
	if (tot >= m) return ;int tp = 0,nl = 0,nr = 0;
	for (Int i = 1;i <= MAXM - 10 && tot <= m;++ tot,++ i){
		++ tp,q[tp].Putin(i),nans[i] += q[tp].r - q[tp].l + 1;
		++ tp,q[tp].Putin(i),nans[i] += q[tp].r - q[tp].l + 1;
		++ tp,q[tp].Putin(i),nans[i] += q[tp].r - q[tp].l + 1;
	}
	for (Int i = 1;3 * i <= tp;++ i) ans[i].set ();sort (q + 1,q + tp + 1,cmp1);
	for (Int i = 1;i <= tp;i += 320){
		int r = min (i + 319,tp);
		sort (q + i,q + r + 1,cmp2);
	}
	for (Int i = 1;i <= tp;++ i){
		if (nr < q[i].l){
			for (Int j = nl;j <= nr;++ j) del (a[j]);nl = q[i].l,nr = q[i].r;
			for (Int j = nl;j <= nr;++ j) ins (a[j]);
		}
		else{
			while (nl < q[i].l) del (a[nl ++]);
			while (nl > q[i].l) ins (a[-- nl]);
			while (nr < q[i].r) ins (a[++ nr]);
			while (nr > q[i].r) del (a[nr --]);
		}
		ans[q[i].t] &= nb;
	}
	for (Int i = nl;i <= nr;++ i) del (a[i]);
	for (Int i = 1;3 * i <= tp;++ i) write (nans[i] - (int)ans[i].count () * 3),putchar ('\n'),nans[i] = 0;
}

signed main(){
	read (n,m);
	for (Int i = 1;i <= n;++ i) read (a[i]),mp[a[i]] ++;map <int,int>::iterator it,it1;
	for (it = mp.begin(),it1 = it,it1 ++;it1 != mp.end();++ it,++ it1) it1 -> second += it -> second;
	for (Int i = 1;i <= n;++ i) a[i] = mp[a[i]];
	Solve (),Solve (),Solve ();
	return 0;
}
```题解 掉进兔子洞
posted @ 2020-07-22 20:55  Dark_Romance  阅读(151)  评论(0编辑  收藏  举报