BZOJ 4939 (Ynoi 2016)掉進兔子洞(莫隊+壓位)

4939: [Ynoi2016]掉進兔子洞

Description

您正在打galgame,然後突然發現您今天太頹了,於是想寫個數據結構題練練手:
一個長爲 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。

Input

第一行兩個數表示 n , m。
第二行 n個數表示 a[i]。
之後 m 行,每行 6 個數 l1 , r1 , l2, r2 , l3 , r3 表示這三個區間。

Output

對於每個詢問,輸出一個數表示答案。

Sample Input

5 2
1 2 2 3 3
1 2 2 3 3 4
1 5 1 5 1 5

Sample Output

3
0

HINT

n , m <= 100000 , 1 <= a[i] <= 1000000000


顯然是要求i=13(rili+1)i=1Maxmin(cnt1[i],cnt2[i],cnt3[i])cntj[i]ij

考慮求後面的部分。首先肯定要離散化。
可以將每個詢問拆成三個,分別處理出每個區間的cnt 數組。而cnt 數組可以用莫隊來得到。

現在考慮如何較快的將三個cnt 取最小後求和。這個可以用bitset 來做到。
考慮離散化的時候,比如樣例1 2 2 3 3,離散化後得到1 2 2 4 4,那麼在bitset 中,就可以用第3個bit位來表示第二個出現的2,用第2個bit位來表示第一個出現的2。然後只需要把三個bitset與起來就得到答案了。


代碼:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<bitset>
#include<cmath>
#define N 100005
using namespace std;
const int T=25000;
bitset<100000>F[25001],f;
int n,A[N],B[N],cnt[N],id[N],S,tot,ans[N],Ans[N],TOT;
bool mark[N];
struct node{int l,r,id;}K[N];
bool cmp(node a,node b)
{
    if(id[a.l]==id[b.l])return a.r<b.r;
    return id[a.l]<id[b.l];
}
void UD(int k,int ty)
{
    k=A[k];cnt[k]+=ty;
    if(ty==1)f[k+cnt[k]-2]=1;
    else f[k+cnt[k]-1]=0;
}
void Solve(int m)
{
    int i,j,k,L,R,l1,l2,l3,r1,r2,r3;
    memset(cnt,0,sizeof(cnt));
    memset(mark,0,sizeof(mark));
    f.reset();tot=0;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d%d%d%d",&l1,&r1,&l2,&r2,&l3,&r3);
        K[++tot]=(node){l1,r1,i};
        K[++tot]=(node){l2,r2,i};
        K[++tot]=(node){l3,r3,i};
        ans[i]=r3+r2+r1-l3-l2-l1+3;
    }
    sort(K+1,K+tot+1,cmp);
    L=1;R=0;
    for(i=1;i<=tot;i++)
    {
        while(R<K[i].r)UD(++R,1);
        while(R>K[i].r)UD(R--,-1);
        while(L<K[i].l)UD(L++,-1);
        while(L>K[i].l)UD(--L,1);
        if(mark[K[i].id])F[K[i].id]&=f;
        else F[K[i].id]=f,mark[K[i].id]=1;
    }
    for(i=1;i<=m;i++)
    {
        k=F[i].count();
        printf("%d\n",ans[i]-3*k);
    }
}
int main()
{
    int i,j,k,m,x,y,l,r;
    scanf("%d%d",&n,&m);S=sqrt(n);
    for(i=j=1;i<=n;i++)scanf("%d",&A[i]),B[i]=A[i],id[i]=i%S?j:j++;
    sort(B+1,B+n+1);
    for(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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章