bzoj4939: [Ynoi2016]掉进兔子洞(莫队 + bitset)

https://www.lydsy.com/JudgeOnline/problem.php?id=4939

ans= r1-l1+1 + r2-l2+1 +r3-l3+1 - ∑ min(cnt1[i],cnt2[i],cnt3[i])*3

计算cnt可以用莫队

关键在与如何对3个区间取小

用bitset

假设5个数为               1 5 5 3 3 

他们离散化之后为      1 4 4 2 2 

那么1对应着bitset的第0位

区间里出现的第一个2对应着bitset的第1位

区间里出现的第二个2对应着bitset的第2位

区间里出现的第一个3对应着bitset的第3位

区间里出现的第二个3对应着bitset的第4位

区间[2,3]的bitset为     0 0 0 1 1

区间[3,4]的bitset为     0 1 0 1 0

这两个bitset执行 & 操作,得到 0 0 0 1 0

1的个数即为 ∑ min(cnt1[i],cnt2[i],cnt3[i])

#include<cmath>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

#define N 100000
#define T 25000

int a[N+1],b[N+1];

int S,bl[N+1];

bitset<N>F[T+1],f;

int cnt[N+1];

bool mark[T+1];
int ans[T+1];

struct node
{
    int id,l,r;
}e[T*3+1];

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

bool cmp(node p,node q)
{
    if(bl[p.l]!=bl[q.l]) return bl[p.l]<bl[q.l];
    return p.r<q.r;
}

void update(int pos,bool ty)
{
    int x=a[pos];
    if(ty)
    {
        cnt[x]++;
        f[x+cnt[x]-2]=1;
    }
    else
    {
        f[x+cnt[x]-2]=0;
        cnt[x]--;
    }
}

void solve(int t)
{
    int n=0;
    memset(mark,false,sizeof(mark));
    memset(ans,0,sizeof(ans));
    for(int i=1;i<=t;++i)
    {
        read(e[++n].l); read(e[n].r);
        e[n].id=i;
        ans[i]+=e[n].r-e[n].l+1;
        read(e[++n].l); read(e[n].r);
        e[n].id=i;
        ans[i]+=e[n].r-e[n].l+1;
        read(e[++n].l); read(e[n].r);
        e[n].id=i;
        ans[i]+=e[n].r-e[n].l+1;
    }
    sort(e+1,e+n+1,cmp);
    f.reset();
    memset(cnt,0,sizeof(cnt));
    int L=1,R=0;
    for(int i=1;i<=n;++i)
    {
        while(R<e[i].r) update(++R,true);
        while(R>e[i].r) update(R--,false);
        while(L<e[i].l) update(L++,false);
        while(L>e[i].l) update(--L,true);
        if(!mark[e[i].id]) F[e[i].id]=f,mark[e[i].id]=true;
        else F[e[i].id]&=f;
    }
    for(int i=1;i<=t;++i) 
    {
        ans[i]-=F[i].count()*3;
        printf("%d
",ans[i]);
    }    
}

int main()
{
    //freopen("xp1.in","r",stdin); 
    //freopen("xp1.ans","w",stdout);
    int n,m;
    read(n); read(m);
    S=sqrt(n);
    for(int i=1;i<=n;++i) bl[i]=(i-1)/S+1;
    for(int i=1;i<=n;++i) read(a[i]),b[i]=a[i];
    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<=T) solve(m),m=0;
        else solve(T),m-=T;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8986891.html