题解 P4688/BZOJ4939 【[Ynoi2016] 掉进兔子洞】

简化题面

给出一个长度为 \(n\) 的序列 \(a\)。有 \(m\) 次询问,每次给出三段区间 \([l_1,r_1],[l_2,r_2],[l_3,r_3​]\),把这三段区间中同时出现的数一个一个删掉,问最后三个区间剩下的数的个数和。

\(n,m\le 10^5\)\(a_i\le 10^9\)

解题思路

既然让我们求剩下的,我们可以将答案转化成三个序列内的所有数-三个序列内重复出现的数的个数,考虑第一部份答案就是对应每组询问三个序列长度之和即可,但是第二部分答案要怎么维护呢。

权值范围很大所以首先需要离散化,然后维护区间内数的种类最简单的方法肯定是用莫队来维护,但是如何维护相同的数,显然可以用\(bitset\)来维护集合交集进行,但是注意到每个区间内重复的数的个数并不为\(1\),会有很多,这就很棘手。

于是我们考虑在离散化的时候并不去重,这样我们对应的每一种元素到下一种元素的下标就是整个序列此元素的个数,那么元素个数维护出来之后考虑莫队转移的时候如何转移,我们维护一个转移用的\(bitset\),对于每一组询问我们同样维护一个\(bitset\),对于\(add\)操作我们只需要在元素下表+元素个数位置变为\(1\),然后个数增加即可,\(del\)操作是也是同样的道理将个数减去然后相应位置变为\(0\)即可,最后每一组询问答案减去每一组询问\(bitset\)\(1\)的个数的三倍就是答案。

同时考虑开\(10^5\times 10^5\)大小的\(bitset\)显然是会炸掉的,于是我们将询问分成四次进行处理即可。

具体细节看代码。

\(\mathcal{Code}\)

// Author: Ame__
#include<bits/stdc++.h>
#include<stdint.h>
#define _ 0
#define AME__DEBUG
#define bomb exit(0)
#define LOG(FMT...) fprintf(stderr , FMT)
#define TOWA(FMT...) fprintf(stdout , FMT)
using namespace std;
/*Grievous Lady*/
    
typedef int32_t i32;
typedef int64_t i64;
typedef double qwq;
    
const int BUF_SIZE = 1 << 12;
char buf[BUF_SIZE] , *buf_s = buf , *buf_t = buf + 1;
    
#define PTR_NEXT() \
{ \
    buf_s ++; \
    if(buf_s == buf_t) \
    { \
        buf_s = buf; \
        buf_t = buf + fread(buf , 1 , BUF_SIZE , stdin); \
    } \
}
    
#define mians(_s_) \
{ \
    while(!isgraph(*buf_s)) PTR_NEXT();\
    char register *_ptr_ = (_s_); \
    while(isgraph(*buf_s) || *buf_s == '-') \
    { \
        *(_ptr_ ++) = *buf_s; \
        PTR_NEXT(); \
    } \
    (*_ptr_) = '\0'; \
}
    
template <typename _n_> void mian(_n_ & _x_){
    while(*buf_s != '-' && !isdigit(*buf_s)) PTR_NEXT();
    bool register _nega_ = false; if(*buf_s == '-'){ _nega_ = true; PTR_NEXT(); }
    _x_ = 0; while(isdigit(*buf_s)){ _x_ = _x_ * 10 + *buf_s - '0'; PTR_NEXT(); } if(_nega_) _x_ = -_x_;
}
    
const i32 kato = 1e5 + 10;
const i32 atri = 2e4 + 5e3 + 10;

template <typename _n_> bool cmax(_n_ &a , const _n_ &b){ return a < b ? a = b , 1 : 0; }
template <typename _n_> bool cmin(_n_ &a , const _n_ &b){ return a > b ? a = b , 1 : 0; }
    
i32 n , m , tot , bol , qaq , l1 , l2 , l3 , r1 , r2 , r3;
i32 ans[kato] , cnt[kato] , a[kato] , b[kato];
bitset<kato> res , Que[atri];
bool vis[kato];

struct node{
    i32 l , r , id;
    friend bool operator <(const node &a , const node &b){
        return (a.l / bol ^ b.l / bol) ? a.l / bol < b.l / bol : (a.l / bol & 1) ? a.r < b.r : a.r > b.r;
    }
}q[kato];

inline void add(i32 x){
    res[a[x] + cnt[a[x]]] = 1;
    cnt[a[x]] ++;
}

inline void del(i32 x){
    cnt[a[x]] --;
    res[a[x] + cnt[a[x]]] = 0;
}

inline void solve(i32 k){
    res.reset() , tot = 0;
    memset(ans , 0 , sizeof ans); memset(vis , 0 , sizeof vis); memset(cnt , 0 , sizeof cnt);
    for(i32 i = 1;i <= k;i ++){
        mian(l1) , mian(r1) , mian(l2) , mian(r2) , mian(l3) , mian(r3);
        q[++ tot] = (node){l1 , r1 , i} , ans[i] += r1 - l1 + 1;
        q[++ tot] = (node){l2 , r2 , i} , ans[i] += r2 - l2 + 1;
        q[++ tot] = (node){l3 , r3 , i} , ans[i] += r3 - l3 + 1;
    }
    sort(q + 1 , q + 1 + tot); i32 l = 1 , r = 0;
    for(i32 i = 1;i <= tot;i ++){
        while(l > q[i].l) add(-- l);
        while(r < q[i].r) add(++ r);
        while(l < q[i].l) del(l ++);
        while(r > q[i].r) del(r --);
        if(!vis[q[i].id]) vis[q[i].id] = 1 , Que[q[i].id] = res;
        else Que[q[i].id] &= res;
    }
    for(i32 i = 1;i <= k;i ++) ans[i] = ans[i] - Que[i].count() * 3;
    for(i32 i = 1;i <= k;i ++) TOWA("%d\n" , ans[i]);
}

inline int Ame_(){
#ifdef AME__
    freopen(".in" , "r" , stdin); freopen(".out" , "w" , stdout); int nol_cl = clock();
#endif
    mian(n) , mian(m) , bol = sqrt(n);
    for(i32 i = 1;i <= n;i ++) mian(a[i]) , b[i] = a[i];
    sort(b + 1 , b + 1 + n);
    for(i32 i = 1;i <= n;i ++) a[i] = lower_bound(b + 1 , b + 1 + n , a[i]) - b;
    i32 qaq = atri - 10;
    for(; m ;) m <= qaq ? (solve(m) , m = 0) : (solve(qaq) , m -= qaq);
#ifdef AME__TIME
    LOG("Time: %dms\n", int((clock() - nol_cl) / (qwq)CLOCKS_PER_SEC * 1000));
#endif
    return ~~(0^_^0); /*さようならプログラム*/
}
    
int Ame__ = Ame_();
    
int main(){;}
posted @ 2021-02-22 17:07  Ame_sora  阅读(90)  评论(0编辑  收藏  举报