题意
题面很长,取重要部分就好了
一个长为 n 的序列 a。
有 m 个询问,每次询问三个区间,把三个区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和,询问独立。
注意这里删掉指的是一个一个删,不是把等于这个值的数直接删完,
比如三个区间是 [1,2,2,3,3,3,3] , [1,2,2,3,3,3,3] 与 [1,1,2,3,3],就一起扔掉了 1 个 1,1 个 2,2 个 3。
题解
这题看了路牌——莫队,什么想法都没有
三个区间莫什么队啊。。
然后我们可以稍作思考,其实答案就是三个区间的个数和-公共部分嘛。。
于是就是要就公共部分
看了看题解,才知道怎么做。。感觉并不难
公共部分其实我们是可以用bitset来维护的
对于每一个数字,一开始的下标为x
第一次的时候就标记x出现了,第二次标记为x+1出现了。。如此类推
就可以解决一个数字出现多次的情况了。。
然后答案就是三个bitset与一下,看一下1的个数就可以了
然后呢,听说这题卡常数(其实我觉得这复杂度本来就有点大,但是给了80s的时限还可以吧),于是要手写bieset
这里大概说一下手写的bitset怎么写:
bitset其实就是bool数组,但是这样太大/慢了
我们考虑将bool数组开为int
然后就可以位压了
每32位压一压。。
这一块一起处理,这样时空复杂度都是1/32了
CODE:(时空垫底)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef unsigned int Int;
const int N=100005 ;
const int M=33334;//这么多操作做一次
int n,m,nn;
int cal[(1<<16)+10];//这个数有多少个1
int belong[N];
struct qa{int x,id;}a[N];
int A[N];//离散化后的数组
int b[N];
int head[N];//离散化后这个值在哪里
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
bool cmp (qa x,qa y){return x.x<y.x;}
int l1[N],r1[N],l2[N],r2[N],l3[N],r3[N];
int ans[N];
void Init ()
{
n=read();m=read();nn=sqrt(n);
for (int u=0;u<(1<<16);u++) cal[u]=cal[u>>1]+(u&1);
for (int u=1;u<=n;u++) belong[u]=(u-1)/nn+1;
for (int u=1;u<=n;u++) {a[u].x=read();a[u].id=u;}
sort(a+1,a+1+n,cmp);
int tot=1;A[a[1].id]=tot;
for (int u=2;u<=n;u++)
{
if (a[u].x!=a[u-1].x) tot++;
A[a[u].id]=tot;
}
for (int u=1;u<=n;u++) b[u]=A[u];
sort(b+1,b+1+n);
for (int u=1;u<=n;u++)
if (b[u]!=b[u-1])
head[b[u]]=u;
for (int u=1;u<=m;u++)
{
l1[u]=read();r1[u]=read();
l2[u]=read();r2[u]=read();
l3[u]=read();r3[u]=read();
ans[u]=(r1[u]-l1[u]+1)+(r2[u]-l2[u]+1)+(r3[u]-l3[u]+1);
}
}
struct qq
{
int l,r,id;
}q[(M+10)*3];int len;
bool cmp1 (qq x,qq y)
{
return belong[x.l]==belong[y.l]?x.r<y.r:belong[x.l]<belong[y.l];
}
struct bs //手写bitset
{
Int S[3125];
inline void vis (int x)//如果之前存在就把它加上,否则减去
{S[x>>5]^=(1U<<(x&31));}
int count ()//有多少个1
{
int tot=0;
for (int u=0;u<=3124;u++)
tot=tot+cal[S[u]>>16]+cal[S[u]&65535];
return tot;
}
void clear (){memset(S,0,sizeof(S));}
}now,c[M+10];
bs operator ^ (bs x,bs y)
{
bs z;
for (int u=0;u<=3124;u++) z.S[u]=(x.S[u]^y.S[u]);
return z;
}
bs operator & (bs x,bs y)
{
bs z;
for (int u=0;u<=3124;u++) z.S[u]=(x.S[u]&y.S[u]);
return z;
}
int h[N];//每个位置使用到的下标
void Del (int x){now.vis(head[x]+h[x]-2);h[x]--;}
void Add (int x){h[x]++;now.vis(head[x]+h[x]-2);}
void solve1 ()
{
now.clear();memset(h,0,sizeof(h));
memset(c,255,sizeof(c));//全部清为1
int l=1,r=0;
sort(q+1,q+1+len,cmp1);
/*for (int u=1;u<=len;u++)
printf("YES:%d %d %d\n",q[u].l,q[u].r,q[u].id);*/
for (int u=1;u<=len;u++)
{
while (l>q[u].l) Add(A[--l]);
while (l<q[u].l) Del(A[l++]);
while (r>q[u].r) Del(A[r--]);
while (r<q[u].r) Add(A[++r]);
c[q[u].id]=c[q[u].id]&now;
//printf("%d %d\n",q[u].id,c[q[u].id].count());
}
}
void solve ()
{
for (int u=1;u<=m;u+=M)
{
len=0;
for (int i=u;i<=u+M-1;i++)
{
if (i>m) break;
q[++len]=qq{l1[i],r1[i],i-u+1};
q[++len]=qq{l2[i],r2[i],i-u+1};
q[++len]=qq{l3[i],r3[i],i-u+1};
}
solve1();
for (int i=u;i<=u+M-1;i++)
{
if (i>m) break;
printf("%d\n",ans[i]-3*c[i-u+1].count());
}
}
}
int main()
{
Init();
solve();
return 0;
}