#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=100005;
const int M=25005;
int a[N],b[N],bel[N],sum[N],ans[N],visit[N];
struct query{int l,r,id;}q[N];
inline bool cmp(query x,query y){return bel[x.l]==bel[y.l]?x.r<y.r:x.l<y.l;}
bitset<N>s[M],now;//NM/8个字节,不会爆
inline void solve(int m){
int tot=0;
memset(sum,0,sizeof(sum));//忘记初始化这个数组,调了半个小时
for(int i=1;i<=m;++i){
visit[i]=0;ans[i]=0;//初始化
for(int j=1;j<=3;++j){
q[++tot].l=read();q[tot].r=read();q[tot].id=i;
ans[i]+=q[tot].r-q[tot].l+1;
}
}
sort(q+1,q+tot+1,cmp);now.reset();int l=1,r=0;
for(int i=1;i<=tot;++i){
//四个while的顺序,先扩大区间,即l--和r++,再考虑缩小区间,即l++和r--.
//刚开始这里随便写的,调了一下午,一直RE
while(l>q[i].l)--l,now[a[l]+sum[a[l]]]=1,++sum[a[l]];
while(r<q[i].r)++r,now[a[r]+sum[a[r]]]=1,++sum[a[r]];
while(r>q[i].r)--sum[a[r]],now[a[r]+sum[a[r]]]=0,--r;
while(l<q[i].l)--sum[a[l]],now[a[l]+sum[a[l]]]=0,++l;
if(!visit[q[i].id])visit[q[i].id]=1,s[q[i].id]=now;//这个询问之前没访问过,先直接赋值
else s[q[i].id]&=now;//否则取交
}
for(int i=1;i<=m;++i)printf("%d\n",ans[i]-3*(int)s[i].count());
}
int main(){
int n=read(),m=read(),unit=sqrt(n);
for(int i=1;i<=n;++i)a[i]=read(),b[i]=a[i],bel[i]=i/unit+1;
sort(b+1,b+n+1);for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+n+1,a[i])-b;//离散化
while(m){if(m<=25000)solve(m),m=0;else solve(25000),m-=25000;}//分成每个部分25000个询问来做
return 0;
}
原文:https://www.cnblogs.com/PPXppx/p/11715631.html