【莫队+bitset】洛谷P4688

刷点素晴日的题 其实是因为父母在家没法玩素晴日

跑出了最劣解也不想卡常,写篇题解纪念一下……

首先肯定是要先离散化一下的,然后考虑如果只是求区间相同颜色的种类的话怎么做

可以开个 \(\texttt{bitset}\) 记录每种颜色有没有出现过,然后对三个区间的 \(\texttt{bitset}\) 合并,答案就是合并后 \(\texttt{bitset}\)\(1\) 的个数

处理出每个区间的 \(\texttt{bitset}\) 可以莫队

发现合并答案时空间会炸,于是考虑对询问分组,我自己大概是每\(5000\)个询问放在一组跑

好的回到原题面,要求求三个区间颜色相同的数的个数。只要在离散化时不去重 ,用\(nxt[x]\) 记录数\(x\)下一个在 \(\texttt{bitset}\) 中的位置就行了,做法还是上面那个。

#include <bits/stdc++.h>
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define FoR(i,x,y,z) for(int i=(x);i<=(y);i+=(z))
#define Rof(i,x,y) for(int i=(x);i>=(y);--i)
#define RoF(i,x,y,z) for(int i=(x);i>=(y);i-=(z))
#define Edge(x) for(int i=head[x],to=e[i].v;i;i=e[i].nxt,to=e[i].v)
typedef long long ll;
const int N=100005;
const int M=5000;
using namespace std;

template<typename T> void rd(T& x){
    T y=0;int f=1;char c=getchar();
    while(c<'0' || c>'9')
    { c=getchar(); if(c=='-')f=-f; }
    while(c>='0' && c<='9') y=y*10+c-'0',c=getchar();
    x=y*f;
}

int a[N],b[N],bl[N],cnt,nxt[N],tim[N],ans[N],L[N][3],R[N][3],n;
bitset<N> tmp,p[M+2];
struct qwq{
    int l,r,id;
    bool operator <(const qwq &x)const
    { return bl[l]==bl[x.l]?(bl[l]&1?r<x.r:r>x.r):bl[l]<bl[x.l]; }
}q[3*M+5];

void add(int t,int x)
{ x=a[x]; if(tim[x]<t) tim[x]=t,nxt[x]=x; tmp[nxt[x]++]=1; }
void del(int x)
{ x=a[x],tmp[--nxt[x]]=0; }
void solve(int t){
    int l=1,r=0; tmp.reset();
    sort(q+1,q+cnt+1);
    For(i,1,cnt){
        while(l>q[i].l) add(t,--l);
        while(r<q[i].r) add(t,++r);
        while(l<q[i].l) del(l++);
        while(r>q[i].r) del(r--);
        p[q[i].id]&=tmp;
    }
    For(i,0,M-1){
        if(t*M+i>n) return;
        ans[t*M+i]-=3*p[i].count();
    }
}

int main(){
//  freopen("in.txt","r",stdin);
//  freopen("wa.txt","w",stdout);
    int m; rd(n),rd(m);
    int block=sqrt(n);
    For(i,1,n) rd(a[i]),b[i]=a[i]; sort(b+1,b+n+1);
    For(i,1,n) a[i]=lower_bound(b+1,b+n+1,a[i])-b;
    For(i,1,n) bl[i]=(i-1)/block+1;
    
    For(i,0,m-1) For(j,0,2){
        rd(L[i][j]),rd(R[i][j]);
        ans[i]+=R[i][j]-L[i][j]+1;
    }
    memset(tim,-1,sizeof(tim));
    For(i,0,(m+M-1)/M){
        cnt=0;
        For(j,i*M,min(m-1,i*M+M-1)){
            p[j%M].set();
            For(k,0,2) q[++cnt]=(qwq){L[j][k],R[j][k],j%M};         
        }
        solve(i);
    }
    For(i,0,m-1) printf("%d\n",ans[i]);
}

猜你喜欢

转载自www.cnblogs.com/PsychicBoom/p/12234544.html
今日推荐