题解 掉进兔子洞
题目大意
给出\(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;
}
```题解 掉进兔子洞