题意
给你一个长度为 n n n的数列,每次询问三个区间共有的数的个数;
题解
对于这种求交或求并的问题,往往会先考虑到使用bitset,但是本题的数据范围太大需要离散化,且bitset无法记录数量,这里就只能在离散化的时候用一点小技巧了:对于重复出现的数我们不需要unique,假如某数第一次出现的编号为 x x x,那么第二次出现它的编号就可以设为 x + 1 x+1 x+1,以此类推,对于这道题,每个区间独立出来考虑,某数在一区间中第一次出现就用它的 x x x编号,第二次出现就用 x + 1 x+1 x+1,这样就相当于把同样的数看做了不同,bitset也就能发挥它的作用了;现在就有了这么一个做法,如果能得到三个区间的数的集合,再 a n d and and一下,就能知道共有的数的个数了,但是有多组询问,该怎么得到每一个询问的三个区间的数集呢,考虑使用莫队,每次区间扩大或缩小时我们都能只花费 O ( n 32 ) O(\frac{n}{32}) O(32n)的代价,就能再原区间的基础上得到新的区间的数集,再把一个询问看成三个区间分别询问,最后再 a n d and and到一起,便能轻松解决本题了;但是一算空间,超了怎么办?把 Q Q Q次询问分三次来进行,这样就只用一次性开 Q 3 \frac{Q}{3} 3Q个bitset了,空间时间也容得下;但是注意离散化时不能加 l o g log log;
#include<bits/stdc++.h>
#define Fst first
#define Snd second
#define RG register
#define mp make_pair
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
typedef long double LD;
typedef unsigned int UI;
typedef unsigned long long ULL;
template<typename T> inline void read(T& x) {
char c = getchar();
bool f = false;
for (x = 0; !isdigit(c); c = getchar()) {
if (c == '-') {
f = true;
}
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - '0';
}
if (f) {
x = -x;
}
}
template<typename T, typename... U> inline void read(T& x, U& ... y) {
read(x), read(y...);
}
const int N=1e5+10;
int n;
int W[N],V[N],CT[N],part[N],ANS[N/3],S[N],M[N];
bitset<N> G,F[N/3];
struct Data {
int l,r,id;
}Q[N];
bool cmp1(int A,int B) {
return W[A]<W[B];
}
bool cmp2(Data A,Data B) {
return part[A.l]==part[B.l]?A.r<B.r:part[A.l]<part[B.l];
}
void Move(int pos,int val) {
int t=M[pos];
if(val<0) G.reset(S[t]+CT[t]-1);
CT[t]+=val;
if(val>0) G.set(S[t]+CT[t]-1);
}
void Solve(int m) {
if(!m) return;
int cnt=0;
for(int i=1;i<=m;++i) {
F[i].set(); ANS[i]=0;
for(int j=0;j<3;++j) ++cnt,read(Q[cnt].l,Q[cnt].r),Q[cnt].id=i,ANS[i]+=Q[cnt].r-Q[cnt].l+1;
}
sort(Q+1,Q+cnt+1,cmp2);
G.reset(); mem(CT,0);
for(int i=1,L=1,R=0;i<=cnt;++i) {
while(R<Q[i].r) Move(++R,1);
while(R>Q[i].r) Move(R--,-1);
while(L<Q[i].l) Move(L++,-1);
while(L>Q[i].l) Move(--L,1);
F[Q[i].id]&=G;
}
for(int i=1;i<=m;++i) printf("%d\n",ANS[i]-3*(int)F[i].count());
}
//#define rua
int main() {
#ifdef rua
freopen("GG.out","w",stdout);
#endif
int m; read(n,m);
int Base=sqrt(n+1),cnt=1,ID=1;
for(int i=1;i<=n;++i) {
read(W[i]); part[i]=ID;
if(cnt==Base) cnt=1,++ID;
else ++cnt;
V[i]=i;
}
sort(V+1,V+n+1,cmp1);
for(int i=1,t=0;i<=n;++i) {
if(W[V[i]]!=W[V[i-1]]) ++t,S[t]=i;
M[V[i]]=t;
}
Solve(min(33334,m));
if(m>=33334) m-=33334;
else m=0;
Solve(min(33333,m));
if(m>=33333) m-=33333;
else m=0;
Solve(min(33333,m));
return 0;
}